forked from Liminiens/grinder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.fs
209 lines (178 loc) · 5.92 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
open System
open System.IO
open Farmer
open Farmer.Builders
open Medallion.Shell
let resourceGroup = "dotnetru-rg"
let acrName = "dotnetruacr"
let logName = "dotnetru-log"
let appName = "vahter-app"
let servicePlanName = "dotnetru-service-plan"
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 "DOTNETRU_DEPLOY_APPID"
let pwd = getEnv "DOTNETRU_DEPLOY_PWD"
let tenant = getEnv "DOTNETRU_DEPLOY_TENANT"
let subscriptionId = getEnv "DOTNETRU_DEPLOY_SUBID"
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 servicePlan = servicePlan {
name servicePlanName
sku WebApp.Sku.B1
operating_system Linux
}
let botApp = webApp {
name appName
app_insights_off
always_on
link_to_service_plan servicePlan
setting "VAHTER_CONFIG" botSettings
docker_ci
docker_use_azure_registry acrName
docker_image "vahter/grinder:latest" ""
}
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_resource servicePlan
add_resource botApp
add_resource logs
}
let addLogsToWebApp = arm {
location Location.NorthEurope
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)
do! azShell.Run("az", "account", "set", "--subscription", subscriptionId)
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
printfn "ACR deployed successfully"
let registryPwd = registryDeploymentResult.["pwd"]
let registryLogin = registryDeploymentResult.["login"]
let registryHost = registryDeploymentResult.["host"]
printfn $"%A{registryDeploymentResult}"
// build&push image to registry
do! pushDockerImage(registryHost, registryLogin, registryPwd)
printfn "Docker image pushed successfully"
// deploy webapp
let! _ =
Deploy.tryExecute
resourceGroup
[ botApp.DockerAcrCredentials.Value.Password.Value, registryPwd ]
appDeployment
printfn "Webapp, log analytic and service plan deployed successfully"
// deploy logs
let! _ =
Deploy.tryExecute
resourceGroup
Deploy.NoParameters
addLogsToWebApp
return printfn "Logs linked with webapp successfully"
}
[<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 ->
failwith $"Unknown arguments %A{x}"
|> Result.get
0