From 7a222ae2a2be432644c6cfad37094ee2b538a1a0 Mon Sep 17 00:00:00 2001 From: francis04j Date: Fri, 20 Dec 2024 20:42:05 +0000 Subject: [PATCH 1/3] added github action with terraform deploy --- .github/workflows/deploy-to-azure.yml | 40 +++++ CubeLogic.TransactionsConverter/Dockerfile | 29 +++- deploy/azure.tf | 181 +++++++++++++++++++++ 3 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/deploy-to-azure.yml create mode 100644 deploy/azure.tf diff --git a/.github/workflows/deploy-to-azure.yml b/.github/workflows/deploy-to-azure.yml new file mode 100644 index 0000000..17c5b4d --- /dev/null +++ b/.github/workflows/deploy-to-azure.yml @@ -0,0 +1,40 @@ +name: Deploy to Azure + +on: + push: + branches: [ "main" ] # Trigger on pushes to the 'main' branch + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Login to Azure + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Change working directory + run: | + cd deploy + + - name: Initialize Terraform + run: | + terraform init -backend-config="config=/dev/null" + + - name: Plan + run: | + terraform plan -out=plan + + - name: Apply + run: | + terraform apply -auto-approve plan + + - name: Output + run: | + terraform output -json > outputs.json \ No newline at end of file diff --git a/CubeLogic.TransactionsConverter/Dockerfile b/CubeLogic.TransactionsConverter/Dockerfile index 0f10348..688327a 100644 --- a/CubeLogic.TransactionsConverter/Dockerfile +++ b/CubeLogic.TransactionsConverter/Dockerfile @@ -14,10 +14,33 @@ FROM mcr.microsoft.com/dotnet/runtime:8.0 # Set the working directory for the runtime container WORKDIR /app +# Create a non-root user +RUN useradd -m -u 1000 appuser + +# Switch to the new user +USER appuser + +# Check permissions for the app user (optional) +RUN ls -l /app && echo "Permissions for /app:" + +# Create empty volumes for each argument path +VOLUME ["--mode=0755", "/app/input_file_path"] +VOLUME ["--mode=0755", "/app/config_file_path"] +VOLUME ["--mode=0755", "/app/output"] + + # Copy the built application from the build stage COPY --from=build-env /out ./ -COPY InputTransactions.csv ./ -COPY config.json ./ + +# Pass arguments as environment variables +ENV INPUT_PATH=/app/InputTransactions.csv +ENV CONFIG_PATH=/app/config.json +ENV OUTPUT_PATH=/app/output/output.csv USER $APP_UID -ENTRYPOINT ["dotnet", "CubeLogic.TransactionsConverter.dll"] +ENTRYPOINT ["sh", "-c", "dotnet CubeLogic.TransactionsConverter.dll --input ${INPUT_PATH} --config ${CONFIG_PATH} --output ${OUTPUT_PATH}"] + +# Example how to run +# folder with input files is called input_file_path +# folder for output file is called output +# docker run -u root -v $(pwd)/input_file_path/inputTransactions.csv:/app/inputTransactions.csv -v $(pwd)/input_file_path/config.json:/app/input_file_path/config.json -v $(pwd)/output:/app/output transconv \ No newline at end of file diff --git a/deploy/azure.tf b/deploy/azure.tf new file mode 100644 index 0000000..7e9af2c --- /dev/null +++ b/deploy/azure.tf @@ -0,0 +1,181 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.14.0" + } + } +} + +provider "azurerm" { + features {} + + +} + +# Resource group +resource "azurerm_resource_group" "rg" { + name = "dotnet-app-rg" + location = "UK South" +} + +# Storage account for input and output files +resource "azurerm_storage_account" "storage" { + name = "dotnetappstorage" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +# Storage container for input files +resource "azurerm_storage_container" "input_files" { + name = "inputfiles" + storage_account_name = azurerm_storage_account.storage.name + container_access_type = "private" +} + +# Storage container for output files +resource "azurerm_storage_container" "output_files" { + name = "outputfiles" + storage_account_name = azurerm_storage_account.storage.name + container_access_type = "blob" +} + + +# Event Grid Topic for input file changes +resource "azurerm_eventgrid_topic" "input_file_changes" { + name = "input-file-changes-topic" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name +} + +# Event Subscription for WebJob +resource "azurerm_eventgrid_event_subscription" "webjob_subscription" { + name = "webjob-subscription" + scope = azurerm_eventgrid_topic.input_file_changes.id + + webhook_endpoint { + url = "http://${azurerm_container_group.container.ip_address}" + } + + included_event_types = ["Microsoft.Storage.BlobCreated", "Microsoft.Storage.BlobDeleted"] + + retry_policy { + max_delivery_attempts = 3 + event_time_to_live = 1440 + } +} + +# Event Subscription for Logic App +resource "azurerm_eventgrid_event_subscription" "logicapp_subscription" { + name = "logicapp-subscription" + scope = azurerm_eventgrid_topic.input_file_changes.id + + webhook_endpoint { + url = azurerm_logic_app_workflow.file_change_email.access_endpoint + } + included_event_types = ["Microsoft.Storage.BlobCreated", "Microsoft.Storage.BlobDeleted"] + + retry_policy { + max_delivery_attempts = 3 + event_time_to_live = 1440 + } +} + +# Azure Container Instance for the WebJob application +resource "azurerm_container_group" "container" { + name = "dotnet-webjob-container" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + + container { + name = "dotnet-webjob" + image = "your-webjob-docker-image:latest" + cpu = "0.5" + memory = "1.5" + + environment_variables = { + AzureWebJobsStorage = azurerm_storage_account.storage.primary_connection_string + } + + volume { + name = "input-volume" + mount_path = "/mnt/input" + + share_name = azurerm_storage_container.input_files.name + storage_account_name = azurerm_storage_account.storage.name + storage_account_key = azurerm_storage_account.storage.primary_access_key + + } + + volume { + name = "output-volume" + mount_path = "/mnt/output" + share_name = azurerm_storage_container.output_files.name + storage_account_name = azurerm_storage_account.storage.name + storage_account_key = azurerm_storage_account.storage.primary_access_key + + } + + } + + restart_policy = "OnFailure" +} + +# Logic App to send emails on input file changes +resource "azurerm_logic_app_workflow" "file_change_email" { + name = "file-change-email-logic-app" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + workflow_schema = jsonencode({ + "$schema" = "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowDefinition.json#" + "actions" = { + "Send_an_email" = { + "inputs" = { + "body" = "File change detected in the input files." + "subject" = "File Change Notification" + "to" = "dynamic-email-list@from-config" + "host" = { + "connectionName" = "office365" + "operationId" = "SendEmail" + "connection" = { + "name" = "@parameters('$connections')['office365']['connectionId']" + } + } + } + "runAfter" = {} + "type" = "ApiConnection" + } + } + "triggers" = { + "When_a_blob_is_added_or_modified" = { + "inputs" = { + "parameters" = { + "blobPath" = "inputfiles/*" + "connection" = { + "name" = "@parameters('$connections')['azureblob']['connectionId']" + } + } + "recurrence" = { + "frequency" = "Minute" + "interval" = 5 + } + } + "metadata" = { + "operationId" = "OnUpdatedFile" + "connectionName" = "azureblob" + } + "type" = "ApiConnection" + } + } + }) +} + + +# Output for container public IP +output "container_ip" { + value = azurerm_container_group.container.ip_address +} From 32369d35939a692b08d53cd10175d43dd9581bb5 Mon Sep 17 00:00:00 2001 From: francis04j Date: Sat, 21 Dec 2024 17:07:49 +0000 Subject: [PATCH 2/3] added workflow to deploy resources and container --- .github/workflows/deploy-to-azure.yml | 37 ++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-to-azure.yml b/.github/workflows/deploy-to-azure.yml index 17c5b4d..5d85402 100644 --- a/.github/workflows/deploy-to-azure.yml +++ b/.github/workflows/deploy-to-azure.yml @@ -2,7 +2,9 @@ name: Deploy to Azure on: push: - branches: [ "main" ] # Trigger on pushes to the 'main' branch + branches: ["main", "terraform-deploy"] # Trigger on pushes to the 'main' branch + pull_request: + branches: ["main"] jobs: build-and-deploy: @@ -11,13 +13,40 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + # Log in to Azure Container Registry (ACR) + - name: Log in to Azure Container Registry + uses: azure/docker-login@v1 + with: + login-server: ${{ secrets.ACR_SERVER }} + username: ${{ secrets.ACR_USERNAME }} + password: ${{ secrets.ACR_PASSWORD }} + + # Build Docker image + - name: Build Docker image + run: | + docker build -t ${{ secrets.ACR_SERVER }}/transconv:latest . + + # Run Snyk security scan + # - name: Run Snyk Security Scan + # uses: snyk/actions/docker@v2 + # with: + # image: ${{ secrets.ACR_SERVER }}/transconv:latest + # args: --severity-threshold=high + # env: + # SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + # Push Docker image to ACR + - name: Push Docker image + run: | + docker push ${{ secrets.ACR_SERVER }}/transconv:latest + - name: Setup Terraform uses: hashicorp/setup-terraform@v2 - name: Login to Azure uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Change working directory run: | @@ -33,8 +62,8 @@ jobs: - name: Apply run: | - terraform apply -auto-approve plan + terraform apply -auto-approve plan - name: Output run: | - terraform output -json > outputs.json \ No newline at end of file + terraform output -json > outputs.json From 6e335f5bc5cf7f8711502e04cf9d6fb8293c038d Mon Sep 17 00:00:00 2001 From: francis04j Date: Sat, 21 Dec 2024 17:18:38 +0000 Subject: [PATCH 3/3] fixed path to docker deploy --- .github/workflows/deploy-to-azure.yml | 2 +- CubeLogic.TransactionsConverter/Dockerfile | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-to-azure.yml b/.github/workflows/deploy-to-azure.yml index 5d85402..e59e0ff 100644 --- a/.github/workflows/deploy-to-azure.yml +++ b/.github/workflows/deploy-to-azure.yml @@ -24,7 +24,7 @@ jobs: # Build Docker image - name: Build Docker image run: | - docker build -t ${{ secrets.ACR_SERVER }}/transconv:latest . + docker build -f CubeLogic.TransactionsConverter/Dockerfile -t ${{ secrets.ACR_SERVER }}/transconv:latest . # Run Snyk security scan # - name: Run Snyk Security Scan diff --git a/CubeLogic.TransactionsConverter/Dockerfile b/CubeLogic.TransactionsConverter/Dockerfile index 688327a..23f98a1 100644 --- a/CubeLogic.TransactionsConverter/Dockerfile +++ b/CubeLogic.TransactionsConverter/Dockerfile @@ -2,11 +2,11 @@ # Set the working directory inside the container WORKDIR /app -COPY ["CubeLogic.TransactionsConverter.csproj", "./"] +COPY ["CubeLogic.TransactionsConverter/CubeLogic.TransactionsConverter.csproj", "./"] RUN dotnet restore # Copy the entire project directory and build the application -COPY . ./ +COPY CubeLogic.TransactionsConverter/ ./ RUN dotnet publish -c Release -o /out /p:UseAppHost=false FROM mcr.microsoft.com/dotnet/runtime:8.0 @@ -20,9 +20,6 @@ RUN useradd -m -u 1000 appuser # Switch to the new user USER appuser -# Check permissions for the app user (optional) -RUN ls -l /app && echo "Permissions for /app:" - # Create empty volumes for each argument path VOLUME ["--mode=0755", "/app/input_file_path"] VOLUME ["--mode=0755", "/app/config_file_path"]