From 910af220c6a70be90b5c155aa82320b10dbd8efe Mon Sep 17 00:00:00 2001 From: Tine Date: Fri, 1 Mar 2024 15:11:34 +0100 Subject: [PATCH] first commit --- .envrc | 7 +++ .gitignore | 9 +++ Dockerfile | 12 ++++ devbox.json | 24 ++++++++ devbox.lock | 110 ++++++++++++++++++++++++++++++++++ example.env | 2 + justfile | 25 ++++++++ requirements.txt | 5 ++ src/app.py | 11 ++++ terraform/.terraform.lock.hcl | 22 +++++++ terraform/main.tf | 67 +++++++++++++++++++++ terraform/outputs.tf | 3 + terraform/providers.tf | 12 ++++ terraform/variables.tf | 4 ++ 14 files changed, 313 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 devbox.json create mode 100644 devbox.lock create mode 100644 example.env create mode 100644 justfile create mode 100644 requirements.txt create mode 100644 src/app.py create mode 100644 terraform/.terraform.lock.hcl create mode 100644 terraform/main.tf create mode 100644 terraform/outputs.tf create mode 100644 terraform/providers.tf create mode 100644 terraform/variables.tf diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..84fc8e5 --- /dev/null +++ b/.envrc @@ -0,0 +1,7 @@ +# Automatically sets up your devbox environment whenever you cd into this +# directory via our direnv integration: + +eval "$(devbox generate direnv --print-envrc)" + +# check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/ +# for more details diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca16f2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +dist/ +.venv/ + +.env + +.terraform +terraform.tfstate* + +__pycache__ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6b320ce --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +# syntax=docker/dockerfile:1.4 +FROM python:3.10-alpine + +WORKDIR /app + +COPY requirements.txt /app +RUN pip3 install -r requirements.txt + +COPY src /app + +ENTRYPOINT [ "python3" ] +CMD [ "app.py" ] diff --git a/devbox.json b/devbox.json new file mode 100644 index 0000000..f3663df --- /dev/null +++ b/devbox.json @@ -0,0 +1,24 @@ +{ + "packages": [ + "just@latest", + "python@3.12", + "python312Packages.pip@latest", + "terraform@latest", + "azure-cli@latest", + "azure-functions-core-tools@latest" + ], + "env": { + "VENV_DIR": ".venv" + }, + "shell": { + "init_hook": [ + ". $VENV_DIR/bin/activate", + "echo 'Welcome to devbox!' > /dev/null" + ], + "scripts": { + "test": [ + "echo \"Error: no test specified\" && exit 1" + ] + } + } +} diff --git a/devbox.lock b/devbox.lock new file mode 100644 index 0000000..48a9a2e --- /dev/null +++ b/devbox.lock @@ -0,0 +1,110 @@ +{ + "lockfile_version": "1", + "packages": { + "azure-cli@latest": { + "last_modified": "2024-02-26T19:46:43Z", + "resolved": "github:NixOS/nixpkgs/548a86b335d7ecd8b57ec617781f5e652ab0c38e#azure-cli", + "source": "devbox-search", + "version": "2.56.0", + "systems": { + "aarch64-darwin": { + "store_path": "/nix/store/dnbzp85nka7wdd3gdk4a7s0vgcv7f3ix-python3.11-azure-cli-2.56.0" + }, + "aarch64-linux": { + "store_path": "/nix/store/m7d0fwpw7zhsnhbr9b67qf780yrficgj-python3.11-azure-cli-2.56.0" + }, + "x86_64-darwin": { + "store_path": "/nix/store/l5kklfbbk9n9i3kj7vzqg4pmmcxy8z77-python3.11-azure-cli-2.56.0" + }, + "x86_64-linux": { + "store_path": "/nix/store/f96pm8sbihjd7cy98f5xyqn54gjfb1ys-python3.11-azure-cli-2.56.0" + } + } + }, + "azure-functions-core-tools@latest": { + "last_modified": "2024-02-26T19:46:43Z", + "resolved": "github:NixOS/nixpkgs/548a86b335d7ecd8b57ec617781f5e652ab0c38e#azure-functions-core-tools", + "source": "devbox-search", + "version": "4.0.5455", + "systems": { + "aarch64-darwin": { + "store_path": "/nix/store/90khpfynpfcxyiflvxj1nw605cc5ndsd-azure-functions-core-tools-4.0.5455" + }, + "x86_64-darwin": { + "store_path": "/nix/store/7n08wfcxk1by25787pw13gi8yk9ql3fb-azure-functions-core-tools-4.0.5455" + }, + "x86_64-linux": { + "store_path": "/nix/store/yb2av5h85h3h76rq0yy9l7wmyipwcyk9-azure-functions-core-tools-4.0.5455" + } + } + }, + "just@latest": { + "last_modified": "2024-02-26T19:46:43Z", + "resolved": "github:NixOS/nixpkgs/548a86b335d7ecd8b57ec617781f5e652ab0c38e#just", + "source": "devbox-search", + "version": "1.24.0", + "systems": { + "aarch64-darwin": { + "store_path": "/nix/store/4y0018ypsv9psa73sz6na2806ndpx5sf-just-1.24.0" + }, + "aarch64-linux": { + "store_path": "/nix/store/gafx9wd70rzrk16jwm1fdmvs0y15knzk-just-1.24.0" + }, + "x86_64-darwin": { + "store_path": "/nix/store/imhg52m87050xjs76mkdlql422n28kvg-just-1.24.0" + }, + "x86_64-linux": { + "store_path": "/nix/store/92k9inba4i5bs7cp0kh99y1f93v407v0-just-1.24.0" + } + } + }, + "python312Packages.pip@latest": { + "last_modified": "2024-02-26T19:46:43Z", + "plugin_version": "0.0.2", + "resolved": "github:NixOS/nixpkgs/548a86b335d7ecd8b57ec617781f5e652ab0c38e#python312Packages.pip", + "source": "devbox-search", + "version": "23.3.1", + "systems": { + "aarch64-darwin": { + "store_path": "/nix/store/mbjlr4zvqp2sn8xikz10cdsxhx4sj4z6-python3.12-pip-23.3.1" + }, + "aarch64-linux": { + "store_path": "/nix/store/2c4w8x04jczy8jjrkin25920100yapyn-python3.12-pip-23.3.1" + }, + "x86_64-darwin": { + "store_path": "/nix/store/fksz4hvb5f5snyy3n01fmwlqjb4dayjc-python3.12-pip-23.3.1" + }, + "x86_64-linux": { + "store_path": "/nix/store/xc1wzb3gvj5a4djwimldwgvlhv31qxs3-python3.12-pip-23.3.1" + } + } + }, + "python@3.12": { + "last_modified": "2024-02-26T19:46:43Z", + "plugin_version": "0.0.3", + "resolved": "github:NixOS/nixpkgs/548a86b335d7ecd8b57ec617781f5e652ab0c38e#python312", + "source": "devbox-search", + "version": "3.12.2", + "systems": { + "aarch64-darwin": { + "store_path": "/nix/store/15k5wj7q3psakinjs1czl6fdfghi5k6d-python3-3.12.2" + }, + "aarch64-linux": { + "store_path": "/nix/store/ks2j3hf91drxzbizlaiyxhbzcjbp015v-python3-3.12.2" + }, + "x86_64-darwin": { + "store_path": "/nix/store/x69mapgywbfgg8p4fdqy76lg0h9gf2kj-python3-3.12.2" + }, + "x86_64-linux": { + "store_path": "/nix/store/n3jf1lkdfakxskzsm4nlhss8mdgmcqhc-python3-3.12.2" + } + } + }, + "terraform@latest": { + "last_modified": "2024-02-24T23:06:34Z", + "resolved": "github:NixOS/nixpkgs/9a9dae8f6319600fa9aebde37f340975cab4b8c0#terraform", + "source": "devbox-search", + "version": "1.7.4" + } + } +} diff --git a/example.env b/example.env new file mode 100644 index 0000000..409730c --- /dev/null +++ b/example.env @@ -0,0 +1,2 @@ +# Name of the app +APP_NAME=python-azure-example diff --git a/justfile b/justfile new file mode 100644 index 0000000..7e08cf6 --- /dev/null +++ b/justfile @@ -0,0 +1,25 @@ +# Always use devbox environment to run commands. +set shell := ["devbox", "run"] +# Load dotenv +set dotenv-load + +export TF_VAR_name := env("APP_NAME") + +# Run server locally +run: + flask --app src/server run + +dependencies: + pip install -r src/requirements.txt + +dependencies-lock: + pip freeze -l > src/requirements.txt + +deploy: + +terraform-apply: + terraform -chdir=terraform init + terraform -chdir=terraform apply + +terraform-destroy: + terraform -chdir=terraform destroy diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d40fb70 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +blinker==1.7.0 +click==8.1.7 +Flask==3.0.2 +itsdangerous==2.1.2 +Werkzeug==3.0.1 diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..8aa1c4e --- /dev/null +++ b/src/app.py @@ -0,0 +1,11 @@ +from flask import Flask + +app = Flask(__name__) + +@app.route("/health") +def health(): + return "OK" + +@app.route("/") +def hello_world(): + return "

Hello, World!

" diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..59a6cca --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,22 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "3.94.0" + constraints = "3.94.0" + hashes = [ + "h1:a51ZYUp5uuboql399mflWZDrErlhhYz0ujJFsc9gjhg=", + "zh:20d102bc63096ade82f8da81c91afaffa858aa56fe9a7ad02f24f5ae5618bc53", + "zh:3ddb9d6173a4fdb9b2352a76324ee321976915544ae66cbb863c7a60f0593f05", + "zh:4bc6c62142f67192d2def11f4fd419c54dddd89a5448af036bfc60b15eb0509a", + "zh:4c5120c2101a51524af32c4220c5e376f97a227730dd92ec0b06ac677e4b39f2", + "zh:585fa7ab876d09899cd2d842f12bc28c34556b4d47919eceadefab6fa47f909f", + "zh:59de7ea462470dee7088fc4deeff48e1ffd286eaca1185c219be68dadde745b8", + "zh:8421a46dd3bc4bc2eb56f7eb9b91cc84a66070b72195a805862c6022adee2da0", + "zh:a2fcb5a091d5944dc50f1e51f53fa4d370810a507fbf4122920d756083d8df19", + "zh:beb6b93a2a16942625bb6ac1e52bf26878e35f5562f3173279423ca66553b6d7", + "zh:c6846892ea68f49c838d90b75793d1f3a866871dd701ccb575b1eecccd4e7051", + "zh:ddd59492b6d5ce4c83f06a5b16c520048f3e9bb898bab4f3910042f5c01ffeda", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..ec8ec56 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,67 @@ +resource "azurerm_resource_group" "main" { + name = var.name + location = "West Europe" +} + +## +# Database +## +resource "azurerm_postgresql_server" "main" { + name = var.name + location = azurerm_resource_group.main.location + resource_group_name = azurerm_resource_group.main.name + + administrator_login = "psqladmin" + administrator_login_password = "H@Sh1CoR3!" + + sku_name = "B_Gen5_1" + version = "11" + storage_mb = 5120 + + public_network_access_enabled = true + ssl_enforcement_enabled = true + ssl_minimal_tls_version_enforced = "TLS1_2" +} + +## +# Container Registry +## +resource "azurerm_container_registry" "main" { + name = replace(var.name, "-", "") + resource_group_name = azurerm_resource_group.main.name + location = azurerm_resource_group.main.location + sku = "Basic" +} + +## +# Application +## +resource "azurerm_log_analytics_workspace" "main" { + name = var.name + location = azurerm_resource_group.main.location + resource_group_name = azurerm_resource_group.main.name + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_container_app_environment" "main" { + name = var.name + location = azurerm_resource_group.main.location + resource_group_name = azurerm_resource_group.main.name + log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id +} +resource "azurerm_container_app" "main" { + name = var.name + container_app_environment_id = azurerm_container_app_environment.main.id + resource_group_name = azurerm_resource_group.main.name + revision_mode = "Single" + + template { + container { + name = "maincontainerapp" + image = "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest" + cpu = 0.25 + memory = "0.5Gi" + } + } +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..59ebba7 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,3 @@ +output "database_fqdn" { + value = azurerm_postgresql_server.main.fqdn +} diff --git a/terraform/providers.tf b/terraform/providers.tf new file mode 100644 index 0000000..0c5d37d --- /dev/null +++ b/terraform/providers.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "3.94.0" + } + } +} + +provider "azurerm" { + features {} +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..3be12d2 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,4 @@ +variable "name" { + description = "The name of the application" + type = string +}