Skip to content

Commit

Permalink
Added Farmer deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
Ayrat Hudaygulov committed Dec 15, 2020
1 parent f9310f8 commit 01f2621
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/azure-deploy-all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Deploy everything to Azure

on: workflow_dispatch

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Deploy everything to Azure
run: |
cd src/Grinder.Farmer
dotnet run --all
22 changes: 22 additions & 0 deletions src/Grinder.Farmer/Grinder.Farmer.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.fs" />
<Content Include="settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="README.MD" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="FSharp.Core" Version="5.0.0" />
<PackageReference Include="Farmer" Version="1.2.0" />
<PackageReference Include="MedallionShell" Version="1.6.2" />
</ItemGroup>

</Project>
185 changes: 185 additions & 0 deletions src/Grinder.Farmer/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
open System
open System.IO
open Farmer
open Farmer.Builders
open Medallion.Shell

let resourceGroup = "vahter-rg"
let acrName = "vahterregistry"
let logName = "vahter-log"
let appName = "vahter-app"

let getEnv name =
match Environment.GetEnvironmentVariable name with
| null ->
failwith $"Provide required ENV variable: {name}"
// Console.WriteLine $"Please provide ENV variable: {name}"
// Console.ReadLine()
| value -> value

let appId = getEnv "VAHTER_DEPLOY_APPID"
let pwd = getEnv "VAHTER_DEPLOY_PWD"
let tenant = getEnv "VAHTER_DEPLOY_TENANT"

type Result.ResultBuilder with
member _.Bind(cmd: Command, next: unit -> Result<'a, string>): Result<'a, string> =
cmd.StandardOutput.PipeToAsync(Console.Out, true) |> ignore
cmd.StandardError.PipeToAsync(Console.Error, true) |> ignore
if cmd.Result.Success then
next()
else
Error cmd.Result.StandardError

let botSettings =
let vahterConfig = Environment.GetEnvironmentVariable "VAHTER_CONFIG"
if File.Exists "./settings.json" then
File.ReadAllText "settings.json"
else if vahterConfig <> null then
vahterConfig
else
failwith "Please put bot settings either 1) in settings.json 2) or in env VAHTER_CONFIG"

let logs = logAnalytics {
name logName

retention_period 30<Days>
enable_query
enable_ingestion
}

let registry = containerRegistry {
name acrName

sku ContainerRegistry.Basic
enable_admin_user
}

let botApp = webApp {
name appName

app_insights_off
always_on
operating_system Linux
sku WebApp.Sku.B1

setting "VAHTER_CONFIG" botSettings

docker_ci
docker_use_azure_registry acrName
docker_image "vahter/grinder:latest" ""

depends_on logs.Name
}

let registryDeployment = arm {
location Location.NorthEurope
add_resource registry
output "host" registry.LoginServer
output "pwd" $"[listCredentials(resourceId('Microsoft.ContainerRegistry/registries','{acrName}'),'2017-10-01').passwords[0].value]"
output "login" $"['{acrName}']"
}

let appDeployment = arm {
location Location.NorthEurope
add_resources [
logs
botApp
]
add_resource (Resource.ofJson $"""
{{
"type": "Microsoft.Web/sites/providers/diagnosticSettings",
"apiVersion": "2017-05-01-preview",
"name": "[concat('{appName}', '/microsoft.insights/', '{logName}')]",
"dependsOn": [],
"properties": {{
"workspaceId": "[resourceId('Microsoft.OperationalInsights/workspaces', '{logName}')]",
"metrics": [],
"logs": [
{{
"category": "AppServiceConsoleLogs",
"enabled": true
}},
{{
"category": "AppServiceAppLogs",
"enabled": true
}},
{{
"category": "AppServiceHTTPLogs",
"enabled": true
}}
]
}}
}}
""")
}

let getAcrCreds() = result {
let azShell = Shell(fun opts ->
opts.ThrowOnError(false)
|> ignore
)
do! azShell.Run("az", "login", "--service-principal", "-u", appId, "-p", pwd, "--tenant", tenant)
let pwd = azShell.Run("az", "acr", "credential", "show", "--name", acrName, "--query", "passwords[0].value")
let pwdStringRaw = pwd.Result.StandardOutput
let pwdString = pwdStringRaw.Substring(1, pwdStringRaw.Length - 3) // truncating first and last chars
return $"{acrName}.azurecr.io", acrName, pwdString
}

let pushDockerImage (host, user, pwd) = result {
let dockerShell = Shell(fun opts ->
opts.ThrowOnError(false)
.WorkingDirectory("../..")
|> ignore
)

do! dockerShell.Run("docker", "login", "-u", user, "-p", pwd, host)
do! dockerShell.Run("docker", "build", ".", "-t", "grinder")
do! dockerShell.Run("docker", "tag", "grinder", $"{host}/vahter/grinder")
do! dockerShell.Run("docker", "push", $"{host}/vahter/grinder")
return ()
}

let deployAll() = result {
// authenticate into Azure
let! authResult = Deploy.authenticate appId pwd tenant
printfn "%A" authResult

// deploying container registry
let! registryDeploymentResult =
Deploy.tryExecute
resourceGroup
Deploy.NoParameters
registryDeployment

let registryPwd = registryDeploymentResult.["pwd"]
let registryLogin = registryDeploymentResult.["login"]
let registryHost = registryDeploymentResult.["host"]

// build&push image to registry
do! pushDockerImage(registryHost, registryLogin, registryPwd)

// deploy webapp with bot
let! deploymentResult =
Deploy.tryExecute
resourceGroup
[ botApp.DockerAcrCredentials.Value.Password.Value, registryPwd ]
appDeployment
return printfn "%A" deploymentResult
}

[<EntryPoint>]
let main argv =
match argv with
| null | [||] ->
// deploy only image
result {
let! host, usr, pwd = getAcrCreds()
do! pushDockerImage(host, usr, pwd)
}
| x when Array.contains "--all" x ->
// deploy everything = resources + image
deployAll()
| x ->
failwithf "Unknown arguments %A" x
|> Result.get
0
28 changes: 28 additions & 0 deletions src/Grinder.Farmer/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#Description
This project will deploy Grinder bot to Azure
There are two scenarios
- Deploy Azure resources together with docker image
- Build and push docker image only into predeployed container registry

To deploy everything pass `--all` argument

To deploy just an image don't pass any argument

#Prerequisites
- AZ CLI
- Docker
- Net5 SDK

- Azure credentials (put them in env variables)
- `VAHTER_DEPLOY_APPID`
- `VAHTER_DEPLOY_PWD`
- `VAHTER_DEPLOY_TENANT`

- Bot settings (pick one)
- `settings.json` file
- `VAHTER_CONFIG` variable

#Run
`dotnet run [args]` (from project folder)

or just run from IDE

0 comments on commit 01f2621

Please sign in to comment.