From c7c982667141296705df6072b4447f2e37eb5227 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 15:23:22 +0100 Subject: [PATCH 01/16] moved to netcoreapp3.1, removed arm --- Dockerfile | 14 +++----------- global.json | 2 +- .../Grinder.DataAccess.csproj | 2 +- .../Grinder.ExportTool.fsproj | 2 +- src/Grinder/Grinder.fsproj | 5 +++-- src/Grinder/Program.fs | 19 +++++++++++++++---- src/Grinder/appsettings.json | 2 +- tests/Grinder.Tests/Grinder.Tests.fsproj | 2 +- 8 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9bbcce5..115b032 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,4 @@ -FROM resin/rpi-raspbian AS QEMU -# We need this container to copy QEMU files and use at ARM container -# This will fix pipeline crashes while doing smth - -FROM mcr.microsoft.com/dotnet/core/sdk:2.2.203-stretch AS build-dotnet +FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-dotnet WORKDIR /app # Copy csproj and restore as distinct layers COPY *.sln ./ @@ -17,12 +13,10 @@ COPY src/Grinder/. ./src/Grinder COPY src/Grinder.Common/. ./src/Grinder.Common COPY src/Grinder.DataAccess/. ./src/Grinder.DataAccess WORKDIR /app/src/Grinder -RUN dotnet publish -r linux-arm -c Release -o out +RUN dotnet publish -r linux-x64 -c Release -o out # Build runtime image -FROM mcr.microsoft.com/dotnet/core/runtime:2.2.4-stretch-slim-arm32v7 -# After COPY we can RUN anything without crashes! -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static +FROM mcr.microsoft.com/dotnet/core/runtime:3.1 WORKDIR /app COPY --from=build-dotnet /app/src/Grinder/out . @@ -31,7 +25,5 @@ RUN mkdir -p /etc/grinder && mkdir -p /app/data VOLUME /etc/grinder/ VOLUME /app/data/ -# In final container we don't need this, removing -RUN rm -f /usr/bin/qemu-arm-static ENTRYPOINT ["dotnet", "Grinder.dll"] diff --git a/global.json b/global.json index b1df68f..d0bfd1d 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.100" + "version": "3.1.300" } } \ No newline at end of file diff --git a/src/Grinder.DataAccess/Grinder.DataAccess.csproj b/src/Grinder.DataAccess/Grinder.DataAccess.csproj index 68b9d7b..23e2b1d 100644 --- a/src/Grinder.DataAccess/Grinder.DataAccess.csproj +++ b/src/Grinder.DataAccess/Grinder.DataAccess.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + netcoreapp3.1 true diff --git a/src/Grinder.ExportTool/Grinder.ExportTool.fsproj b/src/Grinder.ExportTool/Grinder.ExportTool.fsproj index 5a79879..6f1332d 100644 --- a/src/Grinder.ExportTool/Grinder.ExportTool.fsproj +++ b/src/Grinder.ExportTool/Grinder.ExportTool.fsproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 true true diff --git a/src/Grinder/Grinder.fsproj b/src/Grinder/Grinder.fsproj index f507c82..795a112 100644 --- a/src/Grinder/Grinder.fsproj +++ b/src/Grinder/Grinder.fsproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 false true true @@ -15,6 +15,7 @@ + @@ -40,4 +41,4 @@ - + \ No newline at end of file diff --git a/src/Grinder/Program.fs b/src/Grinder/Program.fs index 0dd8b94..0bae48c 100644 --- a/src/Grinder/Program.fs +++ b/src/Grinder/Program.fs @@ -10,6 +10,7 @@ open Funogram.Api open Funogram.Bot open Funogram.Types open FunogramExt +open System module Program = open System.Net.Http @@ -40,10 +41,11 @@ module Program = Bot: BotConfig } - let createHttpClient config = + let createHttpClient (config: Socks5Configuration) = let messageHandler = new HttpClientHandler() - messageHandler.Proxy <- HttpToSocks5Proxy(config.Hostname, config.Port, config.Username, config.Password) - messageHandler.UseProxy <- true + if not (isNull (box config)) then + messageHandler.Proxy <- HttpToSocks5Proxy(config.Hostname, config.Port, config.Username, config.Password) + messageHandler.UseProxy <- true new HttpClient(messageHandler) let createBotApi config (settings: BotSettings) = { @@ -124,11 +126,20 @@ module Program = [] let main _ = - let config = + let mutable configBuilder = ConfigurationBuilder() .AddJsonFile("appsettings.json", false, true) .AddJsonFile("/etc/grinder/appsettings.json", true, true) .AddEnvironmentVariables("Grinder_") + + match Environment.GetEnvironmentVariable("DOTNETRU_APP_CONFIG") with + | null -> () + | connString -> + configBuilder <- configBuilder + .AddAzureAppConfiguration connString + + let config = + configBuilder .Build() .Get() .Bot; diff --git a/src/Grinder/appsettings.json b/src/Grinder/appsettings.json index f9c3834..6e8fec0 100644 --- a/src/Grinder/appsettings.json +++ b/src/Grinder/appsettings.json @@ -3,7 +3,7 @@ "Token": "REPLACEME", "ChannelId": 0, "AdminUserId": 0, - "Socks5Proxy": { + "UNUSED_Socks5Proxy": { "Hostname": "REPLACEME", "Port": 0, "Username": "REPLACEME", diff --git a/tests/Grinder.Tests/Grinder.Tests.fsproj b/tests/Grinder.Tests/Grinder.Tests.fsproj index 4d659f3..7a69813 100644 --- a/tests/Grinder.Tests/Grinder.Tests.fsproj +++ b/tests/Grinder.Tests/Grinder.Tests.fsproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 false false true From 58087194140698eb96c22c6d500ef7b2ae537002 Mon Sep 17 00:00:00 2001 From: Szer Date: Tue, 2 Jun 2020 15:35:13 +0100 Subject: [PATCH 02/16] Create azure-deploy.yml --- .github/workflows/azure-deploy.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/azure-deploy.yml diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml new file mode 100644 index 0000000..d82e320 --- /dev/null +++ b/.github/workflows/azure-deploy.yml @@ -0,0 +1,26 @@ +name: Deploy docker image + +on: + push: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Docker Login + uses: Azure/docker-login@v1 + with: + username: ${{ secrets.AZURE_DOCKER_REGISTRY_USER }} + password: ${{ secrets.AZURE_DOCKER_REGISTRY_PASSWORD }} + login-server: ${{ secrets.AZURE_DOCKER_REGISTRY_SERVER }} + + - name: Build and push Docker images + uses: docker/build-push-action@v1.1.0 + with: + # Docker repository to tag the image with + repository: vahter + # Comma-delimited list of tags. These will be added to the registry/repository to form the image's tags + tags: grinder From a87c49aae6ead8d74b2e26563ae566e230b39faa Mon Sep 17 00:00:00 2001 From: Szer Date: Tue, 2 Jun 2020 15:38:59 +0100 Subject: [PATCH 03/16] Update azure-deploy.yml --- .github/workflows/azure-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index d82e320..4b82f8a 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -17,6 +17,8 @@ jobs: password: ${{ secrets.AZURE_DOCKER_REGISTRY_PASSWORD }} login-server: ${{ secrets.AZURE_DOCKER_REGISTRY_SERVER }} + - uses: actions/checkout@v2 + - name: Build and push Docker images uses: docker/build-push-action@v1.1.0 with: From 4833dd1a34124a4a5cfb682ebd8bbd83ba126066 Mon Sep 17 00:00:00 2001 From: Szer Date: Tue, 2 Jun 2020 16:01:26 +0100 Subject: [PATCH 04/16] Update azure-deploy.yml --- .github/workflows/azure-deploy.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 4b82f8a..75157d7 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -19,10 +19,12 @@ jobs: - uses: actions/checkout@v2 - - name: Build and push Docker images - uses: docker/build-push-action@v1.1.0 - with: - # Docker repository to tag the image with - repository: vahter - # Comma-delimited list of tags. These will be added to the registry/repository to form the image's tags - tags: grinder + - name: Build Docker image + run: docker build . -t grinder --build-arg APP_CONFIG=${{ secrets.BOT_AZURE_APP_CONFIG }} + + - name: Tag Docker image + run: docker tag grinder ${{ secrets.AZURE_DOCKER_REGISTRY_SERVER }}/vahter/grinder + + - name: Push Docker image + run: docker push dotnetru.azurecr.io/vahter/grinder + From 9cef473dcab1b458c782b0703ca69bd9302fe823 Mon Sep 17 00:00:00 2001 From: Szer Date: Tue, 2 Jun 2020 16:04:48 +0100 Subject: [PATCH 05/16] Update azure-deploy.yml --- .github/workflows/azure-deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 75157d7..c42550f 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -15,7 +15,7 @@ jobs: with: username: ${{ secrets.AZURE_DOCKER_REGISTRY_USER }} password: ${{ secrets.AZURE_DOCKER_REGISTRY_PASSWORD }} - login-server: ${{ secrets.AZURE_DOCKER_REGISTRY_SERVER }} + login-server: https://dotnetru.azurecr.io/v1 - uses: actions/checkout@v2 @@ -23,7 +23,7 @@ jobs: run: docker build . -t grinder --build-arg APP_CONFIG=${{ secrets.BOT_AZURE_APP_CONFIG }} - name: Tag Docker image - run: docker tag grinder ${{ secrets.AZURE_DOCKER_REGISTRY_SERVER }}/vahter/grinder + run: docker tag grinder dotnetru.azurecr.io/vahter/grinder - name: Push Docker image run: docker push dotnetru.azurecr.io/vahter/grinder From 70764b4483ba4446ba3acfcda10c6e75c9170ff1 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 16:01:09 +0100 Subject: [PATCH 06/16] fixed Dockerfile --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 115b032..21b9f2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,9 @@ RUN dotnet publish -r linux-x64 -c Release -o out # Build runtime image FROM mcr.microsoft.com/dotnet/core/runtime:3.1 +ARG APP_CONFIG +ENV DOTNETRU_APP_CONFIG ${APP_CONFIG} + WORKDIR /app COPY --from=build-dotnet /app/src/Grinder/out . From 9bc62e4564a8592c88b173f08911c1c0e1fca1c1 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 16:54:14 +0100 Subject: [PATCH 07/16] added ping for debug --- src/Grinder/Commands.fs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Grinder/Commands.fs b/src/Grinder/Commands.fs index 8162ea0..fca42c4 100644 --- a/src/Grinder/Commands.fs +++ b/src/Grinder/Commands.fs @@ -56,7 +56,9 @@ module Parser = | Ban of BanDuration | Unban - type Command = Command of Usernames * CommandAction + type Command = + | UserCommand of Usernames * CommandAction + | Ping let str s = pstring s @@ -107,18 +109,22 @@ module Parser = |> List.map attempt |> choice - let pban: Parser = + let pban: Parser = str "ban" .>> spaces >>. (pforeverBan <|> pdistinctTimeFractions) + |>> Ban let punban: Parser = str "unban" .>> spaces >>% Unban + let pping: Parser = + str "ping" >>% Ping + let pcommandAction: Parser = - (pban |>> Ban) <|> punban + pban <|> punban let parseCommand botUsername = pbotUsername botUsername >>. - pipe2 many1Usernames pcommandAction (fun usernames command -> Command(Usernames(usernames), command)) + (pping <|> pipe2 many1Usernames pcommandAction (fun usernames command -> UserCommand(Usernames(usernames), command))) let runCommandParser botUsername str: ParserResult = run (parseCommand botUsername) str @@ -275,12 +281,13 @@ module Processing = ChatId: TelegramChatId Usernames: UserUsername seq } - + type Command = | BanCommand of BanCommandContext | BanOnReplyCommand of ActionOnReplyCommandContext | UnbanCommand of UnbanCommandContext | UnbanOnReplyCommand of ActionOnReplyCommandContext + | PingCommand | DoNothingCommand type CommandError = @@ -374,7 +381,7 @@ module Processing = let parseTextMessage (context: TextMessageContext): Command = match Parser.parse %context.BotUsername context.MessageText with - | BotCommand(Command((Usernames usernames), Ban(duration))) -> + | BotCommand(UserCommand((Usernames usernames), Ban(duration))) -> let usernames = usernames |> Seq.map ^ fun username -> %username @@ -387,7 +394,7 @@ module Processing = Until = duration } BanCommand context - | BotCommand(Command((Usernames usernames), Unban)) -> + | BotCommand(UserCommand((Usernames usernames), Unban)) -> let usernames = usernames |> Seq.map ^ fun username -> %username @@ -399,6 +406,8 @@ module Processing = Usernames = usernames } UnbanCommand context + | BotCommand(Ping) -> + PingCommand | InvalidCommand _ -> DoNothingCommand @@ -538,6 +547,9 @@ module Processing = } return Some <| UnbanOnReplyMessage(context.From, message, errors) + | PingCommand -> + do! botApi.SendTextToChannel "pong" + return None | DoNothingCommand -> return None } From c7eb7944589e4c922a9f94fde9b3f6cbae424438 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 17:25:35 +0100 Subject: [PATCH 08/16] added response on port 80 --- Dockerfile | 2 ++ src/Grinder/Program.fs | 41 +++++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 21b9f2e..93c302f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,8 @@ RUN dotnet publish -r linux-x64 -c Release -o out # Build runtime image FROM mcr.microsoft.com/dotnet/core/runtime:3.1 +EXPOSE 80 + ARG APP_CONFIG ENV DOTNETRU_APP_CONFIG ${APP_CONFIG} diff --git a/src/Grinder/Program.fs b/src/Grinder/Program.fs index 0bae48c..ec22fcc 100644 --- a/src/Grinder/Program.fs +++ b/src/Grinder/Program.fs @@ -1,5 +1,6 @@ namespace Grinder +open System.Net open Microsoft.Extensions.Configuration open Funogram open Grinder @@ -153,23 +154,31 @@ module Program = GrinderContext.MigrateUp() - async { - printfn "Starting bot" + printfn "Starting bot" + + let settings = { + Token = config.Token + ChatsToMonitor = ChatsToMonitor.Create config.ChatsToMonitor + AllowedUsers = AllowedUsers.Create config.AllowedUsers + ChannelId = %config.ChannelId + AdminUserId = %config.AdminUserId + } + startBot botConfiguration (onUpdate settings (createBotApi botConfiguration settings) dataApi) None + |> Async.Start - let settings = { - Token = config.Token - ChatsToMonitor = ChatsToMonitor.Create config.ChatsToMonitor - AllowedUsers = AllowedUsers.Create config.AllowedUsers - ChannelId = %config.ChannelId - AdminUserId = %config.AdminUserId - } - do! startBot botConfiguration (onUpdate settings (createBotApi botConfiguration settings) dataApi) None - |> Async.StartChild - |> Async.Ignore - - printfn "Bot started" - do! Async.Sleep(-1) - } |> Async.RunSynchronously + printfn "Bot started" + + use listener = new HttpListener() + listener.Prefixes.Add("http://*:80/") + listener.Start() + + let buffer = System.Text.Encoding.UTF8.GetBytes "OK" + + while true do + let ctx = listener.GetContext() + let output = ctx.Response.OutputStream + output.Write(buffer, 0, buffer.Length) + output.Close(); printfn "Bot exited" 0 // return an integer exit code \ No newline at end of file From f4a7e2bb948dbad4c7ecc98914b247ce55b3bfc5 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 17:44:38 +0100 Subject: [PATCH 09/16] deleted env --- .github/workflows/azure-deploy.yml | 2 +- Dockerfile | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index c42550f..05c0a99 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Build Docker image - run: docker build . -t grinder --build-arg APP_CONFIG=${{ secrets.BOT_AZURE_APP_CONFIG }} + run: docker build . -t grinder - name: Tag Docker image run: docker tag grinder dotnetru.azurecr.io/vahter/grinder diff --git a/Dockerfile b/Dockerfile index 93c302f..e229f7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,6 @@ FROM mcr.microsoft.com/dotnet/core/runtime:3.1 EXPOSE 80 -ARG APP_CONFIG -ENV DOTNETRU_APP_CONFIG ${APP_CONFIG} - WORKDIR /app COPY --from=build-dotnet /app/src/Grinder/out . From 41afea044c0bae921b727b8adb031067ad8ab8b2 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 17:48:21 +0100 Subject: [PATCH 10/16] test --- src/Grinder/Program.fs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Grinder/Program.fs b/src/Grinder/Program.fs index ec22fcc..27f13fe 100644 --- a/src/Grinder/Program.fs +++ b/src/Grinder/Program.fs @@ -1,6 +1,7 @@ namespace Grinder open System.Net +open System.Threading open Microsoft.Extensions.Configuration open Funogram open Grinder @@ -168,17 +169,19 @@ module Program = printfn "Bot started" - use listener = new HttpListener() - listener.Prefixes.Add("http://*:80/") - listener.Start() + Thread.Sleep -1 - let buffer = System.Text.Encoding.UTF8.GetBytes "OK" - - while true do - let ctx = listener.GetContext() - let output = ctx.Response.OutputStream - output.Write(buffer, 0, buffer.Length) - output.Close(); +// use listener = new HttpListener() +// listener.Prefixes.Add("http://*:80/") +// listener.Start() +// +// let buffer = System.Text.Encoding.UTF8.GetBytes "OK" +// +// while true do +// let ctx = listener.GetContext() +// let output = ctx.Response.OutputStream +// output.Write(buffer, 0, buffer.Length) +// output.Close(); printfn "Bot exited" 0 // return an integer exit code \ No newline at end of file From 9bec397e6bf20f09634f9b61940814917e3ec0a3 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Tue, 2 Jun 2020 17:55:50 +0100 Subject: [PATCH 11/16] revert test --- src/Grinder/Program.fs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Grinder/Program.fs b/src/Grinder/Program.fs index 27f13fe..842a06c 100644 --- a/src/Grinder/Program.fs +++ b/src/Grinder/Program.fs @@ -166,22 +166,21 @@ module Program = } startBot botConfiguration (onUpdate settings (createBotApi botConfiguration settings) dataApi) None |> Async.Start - + printfn "Bot started" - Thread.Sleep -1 + // Needed for azure web app deploy check. We have to response with anything on port 80 + use listener = new HttpListener() + listener.Prefixes.Add("http://*:80/") + listener.Start() + + let buffer = System.Text.Encoding.UTF8.GetBytes "OK" -// use listener = new HttpListener() -// listener.Prefixes.Add("http://*:80/") -// listener.Start() -// -// let buffer = System.Text.Encoding.UTF8.GetBytes "OK" -// -// while true do -// let ctx = listener.GetContext() -// let output = ctx.Response.OutputStream -// output.Write(buffer, 0, buffer.Length) -// output.Close(); + while true do + let ctx = listener.GetContext() + let output = ctx.Response.OutputStream + output.Write(buffer, 0, buffer.Length) + output.Close(); printfn "Bot exited" 0 // return an integer exit code \ No newline at end of file From dd4a32343c10545b3f85209a6e2059560033e2dc Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Mon, 8 Jun 2020 12:50:57 +0100 Subject: [PATCH 12/16] commented optional section --- src/Grinder/appsettings.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Grinder/appsettings.json b/src/Grinder/appsettings.json index 6e8fec0..2b88449 100644 --- a/src/Grinder/appsettings.json +++ b/src/Grinder/appsettings.json @@ -3,12 +3,13 @@ "Token": "REPLACEME", "ChannelId": 0, "AdminUserId": 0, - "UNUSED_Socks5Proxy": { - "Hostname": "REPLACEME", - "Port": 0, - "Username": "REPLACEME", - "Password": "REPLACEME" - }, +// uncomment if you need proxy +// "Socks5Proxy": { +// "Hostname": "REPLACEME", +// "Port": 0, +// "Username": "REPLACEME", +// "Password": "REPLACEME" +// }, "ChatsToMonitor": [ "REPLACEME" ], From 2cb6e8758ef56e23a650c45cde468c2f336a34e4 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Mon, 21 Dec 2020 13:33:09 +0000 Subject: [PATCH 13/16] Farmer (#1) Added Farmer deployment --- .dockerignore | 4 +- .github/workflows/azure-deploy-all.yml | 16 ++ .github/workflows/azure-deploy.yml | 21 +-- .gitignore | 4 + Directory.Build.props | 1 - Dockerfile | 1 + Grinder.sln | 6 + global.json | 3 +- src/Grinder.Farmer/Grinder.Farmer.fsproj | 22 +++ src/Grinder.Farmer/Program.fs | 185 +++++++++++++++++++++++ src/Grinder.Farmer/README.MD | 28 ++++ src/Grinder/Commands.fs | 2 - src/Grinder/Grinder.fsproj | 20 +-- src/Grinder/Program.fs | 9 +- 14 files changed, 288 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/azure-deploy-all.yml create mode 100644 src/Grinder.Farmer/Grinder.Farmer.fsproj create mode 100644 src/Grinder.Farmer/Program.fs create mode 100644 src/Grinder.Farmer/README.MD diff --git a/.dockerignore b/.dockerignore index db5087d..c238407 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ -bin/ -obj/ +**/bin/ +**/obj/ out/ TestResults/ diff --git a/.github/workflows/azure-deploy-all.yml b/.github/workflows/azure-deploy-all.yml new file mode 100644 index 0000000..8436780 --- /dev/null +++ b/.github/workflows/azure-deploy-all.yml @@ -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 diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 32c6e18..80b0409 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -12,21 +12,8 @@ jobs: runs-on: ubuntu-latest steps: - - name: Docker Login - uses: Azure/docker-login@v1 - with: - username: ${{ secrets.AZURE_DOCKER_REGISTRY_USER }} - password: ${{ secrets.AZURE_DOCKER_REGISTRY_PASSWORD }} - login-server: https://dotnetru.azurecr.io/v1 - - uses: actions/checkout@v2 - - - name: Build Docker image - run: docker build . -t grinder - - - name: Tag Docker image - run: docker tag grinder dotnetru.azurecr.io/vahter/grinder - - - name: Push Docker image - run: docker push dotnetru.azurecr.io/vahter/grinder - + - name: Build and push docker image to registry + run: | + cd src/Grinder.Farmer + dotnet run diff --git a/.gitignore b/.gitignore index 0b9cf70..c3da910 100644 --- a/.gitignore +++ b/.gitignore @@ -265,3 +265,7 @@ __pycache__/ *.db /bot_config.json *.orig + +# Bot deployment settings +/src/Grinder.Farmer/settings.json +/src/Grinder.Farmer/.farmer \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index e3d6f38..6be0b35 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,5 @@ true true true - preview \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2277ceb..cb7fb05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ COPY src/Grinder.Common/Grinder.Common.fsproj ./src/Grinder.Common/Grinder.Commo COPY src/Grinder.DataAccess/Grinder.DataAccess.csproj ./src/Grinder.DataAccess/Grinder.DataAccess.csproj COPY tests/Grinder.Tests/Grinder.Tests.fsproj ./tests/Grinder.Tests/Grinder.Tests.fsproj COPY src/Grinder.ExportTool/Grinder.ExportTool.fsproj ./src/Grinder.ExportTool/Grinder.ExportTool.fsproj +COPY src/Grinder.Farmer/Grinder.Farmer.fsproj ./src/Grinder.Farmer/Grinder.Farmer.fsproj COPY Directory.Build.props ./Directory.Build.props RUN dotnet tool restore RUN dotnet restore -r linux-x64 diff --git a/Grinder.sln b/Grinder.sln index c2109b3..aa886e1 100644 --- a/Grinder.sln +++ b/Grinder.sln @@ -24,6 +24,8 @@ ProjectSection(SolutionItems) = preProject README.md = README.md EndProjectSection EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Grinder.Farmer", "src\Grinder.Farmer\Grinder.Farmer.fsproj", "{1B7B3688-F966-4F62-BDCA-ADF56B4E3160}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -50,6 +52,10 @@ Global {13E2DB48-FA8E-48A1-AD53-DA81EBE63A09}.Debug|Any CPU.Build.0 = Debug|Any CPU {13E2DB48-FA8E-48A1-AD53-DA81EBE63A09}.Release|Any CPU.ActiveCfg = Release|Any CPU {13E2DB48-FA8E-48A1-AD53-DA81EBE63A09}.Release|Any CPU.Build.0 = Release|Any CPU + {1B7B3688-F966-4F62-BDCA-ADF56B4E3160}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B7B3688-F966-4F62-BDCA-ADF56B4E3160}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B7B3688-F966-4F62-BDCA-ADF56B4E3160}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B7B3688-F966-4F62-BDCA-ADF56B4E3160}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/global.json b/global.json index 2ed6663..2bcde83 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "5.0.101" + "version": "5.0.101", + "rollForward": "latestMajor" } } \ No newline at end of file diff --git a/src/Grinder.Farmer/Grinder.Farmer.fsproj b/src/Grinder.Farmer/Grinder.Farmer.fsproj new file mode 100644 index 0000000..0015ab9 --- /dev/null +++ b/src/Grinder.Farmer/Grinder.Farmer.fsproj @@ -0,0 +1,22 @@ + + + + Exe + net5.0 + + + + + + PreserveNewest + + + + + + + + + + + diff --git a/src/Grinder.Farmer/Program.fs b/src/Grinder.Farmer/Program.fs new file mode 100644 index 0000000..1b6d5f0 --- /dev/null +++ b/src/Grinder.Farmer/Program.fs @@ -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 + 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 +} + +[] +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 \ No newline at end of file diff --git a/src/Grinder.Farmer/README.MD b/src/Grinder.Farmer/README.MD new file mode 100644 index 0000000..4e4a321 --- /dev/null +++ b/src/Grinder.Farmer/README.MD @@ -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 diff --git a/src/Grinder/Commands.fs b/src/Grinder/Commands.fs index c12309d..157b016 100644 --- a/src/Grinder/Commands.fs +++ b/src/Grinder/Commands.fs @@ -584,8 +584,6 @@ module Processing = return Some <| UnbanOnReplyMessage(context.From, message, errors) | PingCommand context -> - sprintf "Sending PONG to %A" context.ChatId - |> logInfo do! botApi.SendTextMessage context.ChatId "pong" return None | DoNothingCommand -> diff --git a/src/Grinder/Grinder.fsproj b/src/Grinder/Grinder.fsproj index f05cd9b..6de8a98 100644 --- a/src/Grinder/Grinder.fsproj +++ b/src/Grinder/Grinder.fsproj @@ -5,18 +5,18 @@ - + - + - - - - - - - - + + + + + + + + diff --git a/src/Grinder/Program.fs b/src/Grinder/Program.fs index af249d1..edf2c0a 100644 --- a/src/Grinder/Program.fs +++ b/src/Grinder/Program.fs @@ -1,5 +1,6 @@ namespace Grinder +open System.IO open System.Net open Microsoft.Extensions.Configuration open Funogram @@ -222,7 +223,13 @@ module Program = .AddJsonFile("appsettings.json", false, true) .AddJsonFile("/etc/grinder/appsettings.json", true, true) .AddEnvironmentVariables("Grinder_") - + + match Environment.GetEnvironmentVariable("VAHTER_CONFIG") with + | null -> () + | config -> + configBuilder <- configBuilder + .AddJsonStream(new MemoryStream(System.Text.Encoding.ASCII.GetBytes config)) + match Environment.GetEnvironmentVariable("DOTNETRU_APP_CONFIG") with | null -> () | connString -> From d048811e4c9eee3a78b015268c8c2dd745f04118 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Mon, 21 Dec 2020 13:39:42 +0000 Subject: [PATCH 14/16] fixed build (#3) Co-authored-by: Ayrat Hudaygulov --- src/Grinder.Farmer/Grinder.Farmer.fsproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Grinder.Farmer/Grinder.Farmer.fsproj b/src/Grinder.Farmer/Grinder.Farmer.fsproj index 0015ab9..706d14c 100644 --- a/src/Grinder.Farmer/Grinder.Farmer.fsproj +++ b/src/Grinder.Farmer/Grinder.Farmer.fsproj @@ -7,9 +7,6 @@ - - PreserveNewest - From 8bfdd40cab0b1689ee5ae21eb5f472e2a296ce1b Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Mon, 21 Dec 2020 13:48:17 +0000 Subject: [PATCH 15/16] fixed build (#4) Co-authored-by: Ayrat Hudaygulov --- .github/workflows/azure-deploy-all.yml | 5 ++++- .github/workflows/azure-deploy.yml | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/azure-deploy-all.yml b/.github/workflows/azure-deploy-all.yml index 8436780..a837365 100644 --- a/.github/workflows/azure-deploy-all.yml +++ b/.github/workflows/azure-deploy-all.yml @@ -9,8 +9,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Deploy everything to Azure + env: + VAHTER_DEPLOY_APPID: ${{ secrets.VAHTER_DEPLOY_APPID }} + VAHTER_DEPLOY_PWD: ${{ secrets.VAHTER_DEPLOY_PWD }} + VAHTER_DEPLOY_TENANT: ${{ secrets.VAHTER_DEPLOY_TENANT }} run: | cd src/Grinder.Farmer dotnet run --all diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 80b0409..1c47fc3 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -14,6 +14,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build and push docker image to registry + env: + VAHTER_DEPLOY_APPID: ${{ secrets.VAHTER_DEPLOY_APPID }} + VAHTER_DEPLOY_PWD: ${{ secrets.VAHTER_DEPLOY_PWD }} + VAHTER_DEPLOY_TENANT: ${{ secrets.VAHTER_DEPLOY_TENANT }} run: | cd src/Grinder.Farmer dotnet run From 4677727a0c8799aeeb49fcf8721b56bee2647977 Mon Sep 17 00:00:00 2001 From: Ayrat Hudaygulov Date: Mon, 21 Dec 2020 13:50:27 +0000 Subject: [PATCH 16/16] fixed build --- .github/workflows/azure-deploy-all.yml | 1 + .github/workflows/azure-deploy.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/azure-deploy-all.yml b/.github/workflows/azure-deploy-all.yml index a837365..d9ea875 100644 --- a/.github/workflows/azure-deploy-all.yml +++ b/.github/workflows/azure-deploy-all.yml @@ -14,6 +14,7 @@ jobs: VAHTER_DEPLOY_APPID: ${{ secrets.VAHTER_DEPLOY_APPID }} VAHTER_DEPLOY_PWD: ${{ secrets.VAHTER_DEPLOY_PWD }} VAHTER_DEPLOY_TENANT: ${{ secrets.VAHTER_DEPLOY_TENANT }} + VAHTER_CONFIG: ${{ secrets.VAHTER_CONFIG }} run: | cd src/Grinder.Farmer dotnet run --all diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 1c47fc3..29d11b7 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -18,6 +18,7 @@ jobs: VAHTER_DEPLOY_APPID: ${{ secrets.VAHTER_DEPLOY_APPID }} VAHTER_DEPLOY_PWD: ${{ secrets.VAHTER_DEPLOY_PWD }} VAHTER_DEPLOY_TENANT: ${{ secrets.VAHTER_DEPLOY_TENANT }} + VAHTER_CONFIG: ${{ secrets.VAHTER_CONFIG }} run: | cd src/Grinder.Farmer dotnet run