From 33361c4fcf02dc3b6a85bcc7e07e403b9edfbb30 Mon Sep 17 00:00:00 2001 From: Bruno Date: Mon, 18 Apr 2022 19:38:53 -0300 Subject: [PATCH] feat: multidatabase & pfx --- docker/.env | 1 - docker/docker-compose-local.yml | 46 ++++++++------ docker/nginx/Dockerfile | 2 +- docker/nginx/conf.d/devstore.conf | 57 ++++++++++++++++++ docker/nginx/nginx.prod.conf | 43 ------------- docker/pfx/devstore.academy.localhost | Bin 2293 -> 0 bytes docker/pfx/devstore.crt | 17 ------ docker/pfx/devstore.csr | 15 ----- docker/pfx/devstore.rsa | 27 --------- .../Configuration/DbHealthChecker.cs | 2 +- .../DatabaseFlavor/ContextConfiguration.cs | 26 ++++++++ .../DatabaseFlavor/DatabaseType.cs | 9 +++ .../DatabaseFlavor/ProviderConfiguration.cs | 43 +++++++++++++ .../DatabaseFlavor/ProviderSelector.cs | 43 +++++++++++++ .../DevStore.WebAPI.Core.csproj | Bin 1474 -> 2284 bytes .../Configuration/ApiConfig.cs | Bin 3454 -> 3492 bytes .../appsettings.Development.json | 3 +- .../appsettings.Docker.json | 2 +- .../Configuration/IdentityConfig.cs | Bin 3278 -> 3380 bytes .../DevStore.Identity.API/appsettings.json | 5 +- 20 files changed, 212 insertions(+), 129 deletions(-) delete mode 100644 docker/.env create mode 100644 docker/nginx/conf.d/devstore.conf delete mode 100644 docker/nginx/nginx.prod.conf delete mode 100644 docker/pfx/devstore.academy.localhost delete mode 100644 docker/pfx/devstore.crt delete mode 100644 docker/pfx/devstore.csr delete mode 100644 docker/pfx/devstore.rsa create mode 100644 src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ContextConfiguration.cs create mode 100644 src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/DatabaseType.cs create mode 100644 src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderConfiguration.cs create mode 100644 src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderSelector.cs diff --git a/docker/.env b/docker/.env deleted file mode 100644 index 46fd6f1..0000000 --- a/docker/.env +++ /dev/null @@ -1 +0,0 @@ -COMPOSE_PROJECT_NAME=devStore \ No newline at end of file diff --git a/docker/docker-compose-local.yml b/docker/docker-compose-local.yml index 2afb69d..b84111c 100644 --- a/docker/docker-compose-local.yml +++ b/docker/docker-compose-local.yml @@ -3,23 +3,23 @@ version: "3" services: devstore-rabbit: - image: rabbitmq:management + image: rabbitmq:3-management container_name: devstore-rabbit ports: - 5672:5672 - 15672:15672 environment: - RABBITMQ_DEFAULT_USER: devstore - RABBITMQ_DEFAULT_PASS: devstore + RABBITMQ_DEFAULT_USER: "devstore" + RABBITMQ_DEFAULT_PASS: "devstore" sql-server: - image: mcr.microsoft.com/mssql/server:2017-latest - container_name: devstore-sql-server - ports: - - 1433:1433 - environment: - SA_PASSWORD: "MyDB@123" - ACCEPT_EULA: "Y" + image: mcr.microsoft.com/mssql/server:2017-latest + container_name: devstore-sql-server + expose: + - 1433 + environment: + SA_PASSWORD: "MyDB@123" + ACCEPT_EULA: "Y" web-mvc: image: desenvolvedorio/devstore-web-mvc-ecommerce:latest @@ -41,7 +41,7 @@ services: - api-identity - api-customers - api-bff-checkout - + api-identity: image: desenvolvedorio/devstore-api-identity:latest container_name: devstore-api-identity @@ -59,7 +59,7 @@ services: depends_on: - devstore-rabbit - sql-server - + api-cart: image: desenvolvedorio/devstore-api-cart:latest container_name: devstore-api-cart @@ -136,7 +136,7 @@ services: - api-cart - api-billing - api-order - + api-billing: image: desenvolvedorio/devstore-api-billing:latest container_name: devstore-api-billing @@ -156,7 +156,7 @@ services: - api-identity - api-order - sql-server - + api-order: image: desenvolvedorio/devstore-api-order:latest container_name: devstore-api-order @@ -183,9 +183,11 @@ services: context: ./ dockerfile: ./nginx/Dockerfile restart: always + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d:ro ports: - - "80:80" - - "443:443" + - "7500:80" + - "7501:443" depends_on: - web-mvc @@ -195,10 +197,14 @@ services: volumes: - ./certs:/https:rw command: > - sh -c "[ -e "./https/devstore.academy-localhost.pfx" ] && echo File Already exist || (openssl genrsa -out devstore.rsa 2048 && + sh -c "[ -e "./https/devstore.academy-localhost.pfx" ] && echo File Already exist || ( + rm /https/devstore.academy-localhost.pfx && + openssl genrsa -out devstore.rsa 2048 && openssl req -sha256 -new -key devstore.rsa -out devstore.csr -subj '/CN=localhost' && - openssl x509 -req -sha256 -days 1825 -in devstore.csr -signkey devstore.rsa -out devstore.crt && - openssl pkcs12 -export -out /https/devstore.academy-localhost.pfx -inkey devstore.rsa -in devstore.crt -password pass:9HoGMnb7Lu8NFdHBz4Vq2rtKivzMhmMXhtvuB4TZcLMmbWfFmDQCjJeLURAJ4GYe)" + openssl x509 -req -sha256 -days 365 -in devstore.csr -signkey devstore.rsa -out devstore.crt && + openssl pkcs12 -export -out /https/devstore.academy-localhost.pfx -inkey devstore.rsa -in devstore.crt -password pass:9HoGMnb7Lu8NFdHBz4Vq2rtKivzMhmMXhtvuB4TZcLMmbWfFmDQCjJeLURAJ4GYe && + rm devstore.rsa devstore.csr devstore.crt)" volumes: - dpkeys: \ No newline at end of file + dpkeys: + diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile index 3eec141..ef00a1e 100644 --- a/docker/nginx/Dockerfile +++ b/docker/nginx/Dockerfile @@ -1,4 +1,4 @@ FROM nginx -COPY nginx/nginx.prod.conf /etc/nginx/nginx.conf +COPY nginx/devstore.conf /etc/nginx/conf.d/devstore.conf COPY nginx/nerdstore-certificate.pem /etc/nginx COPY nginx/nerdstore-certificate.key /etc/nginx \ No newline at end of file diff --git a/docker/nginx/conf.d/devstore.conf b/docker/nginx/conf.d/devstore.conf new file mode 100644 index 0000000..23c40ba --- /dev/null +++ b/docker/nginx/conf.d/devstore.conf @@ -0,0 +1,57 @@ + +upstream web-mvc { + server web-mvc:5001; +} + +upstream rabbitmq { + least_conn; + server devstore-rabbit:15672; +} + +server { + listen 80; + server_name $hostname; + + location /rabbitmq/ { + rewrite ^/rabbitmq/(.*)$ /$1 break; + proxy_pass http://rabbitmq; + proxy_buffering off; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location / { + # Google doesn't like 302 redirects, so we use a 301 here + return 301 https://$host:7501$request_uri; + } +} + +server { + listen 443 ssl; + server_name $hostname; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + ssl_certificate /etc/nginx/nerdstore-certificate.pem; + ssl_certificate_key /etc/nginx/nerdstore-certificate.key; + + location /rabbitmq/ { + return 302 http://$host:7500$request_uri; + } + + location / { + proxy_pass http://web-mvc; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Connection keep-alive; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $server_name; + } + +} \ No newline at end of file diff --git a/docker/nginx/nginx.prod.conf b/docker/nginx/nginx.prod.conf deleted file mode 100644 index f4fdf84..0000000 --- a/docker/nginx/nginx.prod.conf +++ /dev/null @@ -1,43 +0,0 @@ -worker_processes auto; -events { worker_connections 1024; } - -http { - - sendfile on; - - upstream web-mvc { - server web-mvc:5001; - } - - server { - listen 80; - server_name $hostname; - - location / { - return 301 https://$host$request_uri; - } - } - - server { - listen 443 ssl; - server_name $hostname; - - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - - ssl_certificate /etc/nginx/nerdstore-certificate.pem; - ssl_certificate_key /etc/nginx/nerdstore-certificate.key; - - location / { - proxy_pass http://web-mvc; - proxy_redirect off; - proxy_http_version 1.1; - proxy_set_header Connection keep-alive; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $server_name; - } - } -} \ No newline at end of file diff --git a/docker/pfx/devstore.academy.localhost b/docker/pfx/devstore.academy.localhost deleted file mode 100644 index 5c492faff9d5bcec75f95c07bca4c1287aa312e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2293 zcmY+Ec{CJ^8pda%8Cz%&LP8?TSn?IJWywgWY}uKSB|d{mC1#ARWE;E6GO~<(gb00h z35`A3Df@0Prm;-iI_KW|-TTLT-gAD>InRH;2SI>tgMeTJ0b0Wfla0C_#oz><0Ok^) zWC#J8{|o0L2w>}fBGz02`1&uT4*~*yy{rEuK*SkVwtqKp09g@S5GZ+K6&vAQxd8$} z0eAwKJ9cKpo{c#Om_HEfo8Be$`9dD3;H!0&UCl$`yHge#ifQ}@kl6JP_7m(tE%Oa(}p8@ zH;XQZ+MPMq8rin?{$b8FC(jivn?anYn0Rdq%;alh#X99}L}3Tyle0rmg6`(W!A0+I z)l3D5aM!6A#9Ziu#>0bt=na4H*}YaaZIz0@`BBG^VPxrAfCR#!m8$jLbG`IL!Dr{xK3VcxzD$^YapEJOp@iiar;*u&fs#RZi&&S z{r3!NP7t&6iFPB&rDbK(K~Hl_NAz8Xv-P!3em)C$YNL${He87E(yoNmU~YA6A-6*< zy}X5fq_$WW3t2gs&ew1|7jN~Jb9dOKisl>zdAbvk2x*R0rU(y58)Uk(g00mQ5f-G= z__J!sm{xslxy?cX7HrV&zA>Z^r>aTS&AeOd1YWom6YXdtjjD7oYpT`gadI*M*C~j@ zZ^tG#WVGI@A-_7}M(~zLCgKJDz!V;V+$C9YR;`kfGh(F&Gq=>2)(}GGi)XyTq+W6D_%F91K)`2UMO2L71f;L#ZV4wrh5|0;{#D zx?R@2xsvduzj&QP7KeMS@eX&I<+FAC*x{`{?Dj8YleTpFx`WJO<&net(-*&ORcEvF zQ}Hr}Xas>p_kRS+C9o(%2rLS}uifQcSZ@7*@?P3%z?4OrH2{{2B5ek zF_`UAAAJ^KV}HSKZeE!onImK)k{{7FM?NBF)2)3!%fo#UN6Vyz3u3s`gFamInc9~3 z(%wv_@4Jb@!Rjq<1a+RX z)i`KHSy^F=miS4Yak~RgMW(HPV%7A!RIs=!j5EX3qZVd()@7*YXtl;=cA}TG#G)~) zvz+++Sh^-!UBksD?8oo~Ah@WmeYeM!!hY#5R<#B;oL4h}l{q6SH9HH2_F7 zzkobl_dKI}XKRi+wUZK77{|87|M}{7is#(7tzZLj)ivI6KzB@uOFU<1mdzx?8m`&q zGM{434B!m>SemIHNYk{l85l3}_Z=99H9#)EVo;GgD~|e)H2ZFxnOx~5=o#SR75GJp z@`o0s_YN{E*wbc9K)ZD@(o zuMY|kk%M*N17|4P6Jle3v-TR98Tr-z6|5vr;9hXx&U`7=Bjyl0E}^|z{c zD>`ge7?mUrF@S5mh$1W$9u(8K~J&$Vv;QO|#)o~3b zr&?T{r}Bz}%ctAt0+iLGd1PX1tP^zRklvGT?JG|j?JBm2^y#g~A(l5Nma66}xwzj(|}bXO-1= z+<7()%k7P8!pt7spXfFNw^a%l_(_I708GeB&&YmB=uC?GdqqU;O$M}sMNUrf?$lcH zkkRn{KwHcHS=7Zxc-?QJO<6Y!QWevE)#ju5ma;t|mi7D;cEV}|EHy>km5Tn%DEG8D zVILWt5eF)SC(bOJIi^b7RtDZb2Ofx!>M1Z@s`sj*<%P{k1yQIQr>C)WRFj{!?83t* zN0lzJ_u#Dt> zuBelxM|5y19wd`&F6A#^b(`;5nMCT_MgJK3P?(P**^TcX%c|UHE`p9USb2BF&LwunYS?XE?#S{+cthxw9%D6(Ja3lAl5zr$nR;@x%Q8%gWm zO=wMY3u#$cvxiDj)J^_j8-LBpH?@=&iX7cJW|;2t3Em_!!0d#f2 +/// SqlServer configuration +/// +public static class ContextConfiguration +{ + + /// + /// ASP.NET Identity Context config + /// + public static IServiceCollection PersistStore(this IServiceCollection services, Action databaseConfig) where TContext : DbContext + { + // Add a DbContext to store Keys. SigningCredentials and DataProtectionKeys + if (services.All(x => x.ServiceType != typeof(TContext))) + services.AddDbContext(databaseConfig); + return services; + } + + +} \ No newline at end of file diff --git a/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/DatabaseType.cs b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/DatabaseType.cs new file mode 100644 index 0000000..50b674e --- /dev/null +++ b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/DatabaseType.cs @@ -0,0 +1,9 @@ +namespace DevStore.WebAPI.Core.DatabaseFlavor; + +public enum DatabaseType +{ + SqlServer, + MySql, + Postgre, + Sqlite, +} \ No newline at end of file diff --git a/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderConfiguration.cs b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderConfiguration.cs new file mode 100644 index 0000000..87cc38b --- /dev/null +++ b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderConfiguration.cs @@ -0,0 +1,43 @@ +using System; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using MySqlConnector; + +namespace DevStore.WebAPI.Core.DatabaseFlavor; + +public class ProviderConfiguration +{ + private readonly string _connectionString; + public static ProviderConfiguration With; + private static readonly string MigrationAssembly = typeof(ProviderConfiguration).GetTypeInfo().Assembly.GetName().Name; + + public static void Build(string connString) + { + if (With is null) + With = new ProviderConfiguration(connString); + } + + public ProviderConfiguration(string connString) => _connectionString = connString; + + public Action SqlServer => + options => options.UseSqlServer(_connectionString, sql => sql.MigrationsAssembly(MigrationAssembly)); + + public Action MySql => + options => options.UseMySql(_connectionString, ServerVersion.AutoDetect(_connectionString), sql => sql.MigrationsAssembly(MigrationAssembly)); + + public Action Postgre => + options => options.UseNpgsql(_connectionString, sql => sql.MigrationsAssembly(MigrationAssembly)); + + public Action Sqlite => + options => options.UseSqlite(_connectionString, sql => sql.MigrationsAssembly(MigrationAssembly)); + + + /// + /// it's just a tuple. Returns 2 parameters. + /// Trying to improve readability at ConfigureServices + /// + public static (DatabaseType, string) DetectDatabase(IConfiguration configuration) => ( + configuration.GetValue("AppSettings:DatabaseType"), + configuration.GetConnectionString("DefaultConnection")); +} \ No newline at end of file diff --git a/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderSelector.cs b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderSelector.cs new file mode 100644 index 0000000..bf3b13f --- /dev/null +++ b/src/building-blocks/DevStore.WebAPI.Core/DatabaseFlavor/ProviderSelector.cs @@ -0,0 +1,43 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using static DevStore.WebAPI.Core.DatabaseFlavor.ProviderConfiguration; + +namespace DevStore.WebAPI.Core.DatabaseFlavor +{ + public static class ProviderSelector + { + public static IServiceCollection ConfigureProviderForContext( + this IServiceCollection services, + (DatabaseType, string) options) where TContext : DbContext + { + var (database, connString) = options; + Build(connString); + return database switch + { + DatabaseType.SqlServer => services.PersistStore(With.SqlServer), + DatabaseType.MySql => services.PersistStore(With.MySql), + DatabaseType.Postgre => services.PersistStore(With.Postgre), + DatabaseType.Sqlite => services.PersistStore(With.Sqlite), + + _ => throw new ArgumentOutOfRangeException(nameof(database), database, null) + }; + } + + public static Action WithProviderAutoSelection((DatabaseType, string) options) + { + var (database, connString) = options; + Build(connString); + return database switch + { + DatabaseType.SqlServer => With.SqlServer, + DatabaseType.MySql => With.MySql, + DatabaseType.Postgre => With.Postgre, + DatabaseType.Sqlite => With.Sqlite, + + _ => throw new ArgumentOutOfRangeException(nameof(database), database, null) + }; + } + + } +} diff --git a/src/building-blocks/DevStore.WebAPI.Core/DevStore.WebAPI.Core.csproj b/src/building-blocks/DevStore.WebAPI.Core/DevStore.WebAPI.Core.csproj index 096bbc75dcbfd7e4a80431d37833e553b3c43d5c..c2e0770b9b7e08cac6ecb050a8ee83651e8d2ac9 100644 GIT binary patch delta 193 zcmX@a{YG%Z8J5Xzj55j!3_c8r3`q>B3^@$83`z_xKwb%0B$1&QC|b;*G&zycb@Ce~ zvB@4xYJ$NGg+P_TK$#+jG7verktv(okD-7e9jF#4H`$prMX0as&WMsV`yx delta 21 dcmaDOc!+z$8J39$SSFugk(szlV6qy=F#u`*2>}2A diff --git a/src/services/DevStore.Billing.API/Configuration/ApiConfig.cs b/src/services/DevStore.Billing.API/Configuration/ApiConfig.cs index 9021293ac3e4c7db187fb8292253f18ee5dd8ca9..a2ef0bdfaf5086b55ec5bcb1a855d2e28d78892b 100644 GIT binary patch delta 189 zcmew-wM2Tt5os5OM1~R|P6Fa$hExVOh8!TPj3J+)XrjI9#5GSQ-(h?(IggQtyBMsl zgdvk5dGbXj(TQs$bn$3r&|?T-C;}Q&2Go!OG`MK;dq&00dzfx9PS#=*5=D~)+6%OC e@_ZIUpo>z0Hl;Eo14%RsChN1xZl1^bfE@r7%P}7S delta 204 zcmZ1?{ZDGbk;yWQXO#08N*FSMxRSw*p@<=oA(tVQp`0Nf$j)YP2GgmN4>Ac)wqq2T zJda6i@*l=Co1>U-F>*RGqyV7{L(=4ER>R3s>;{t`uyRZ;U>6V%Whe$363kG@kOL%B zfku^q$jS9=s-7St^MEjwAsK8jh!+fG6#*TQ$B@pT!Jq^*GnF9?=#)~R{t~bw&~+#= PXimP!=DeAWZ5}%SefTlv diff --git a/src/services/DevStore.Billing.API/appsettings.Development.json b/src/services/DevStore.Billing.API/appsettings.Development.json index 4db4eba..780c752 100644 --- a/src/services/DevStore.Billing.API/appsettings.Development.json +++ b/src/services/DevStore.Billing.API/appsettings.Development.json @@ -15,7 +15,8 @@ "AppSettings": { "JwksUri": "https://localhost:5421/jwks", "Issuer": "https://devstore.academy", - "Audience": "DevStore" + "Audience": "DevStore", + "DatabaseType": "SqlServer" }, "BillingConfig": { "DefaultApiKey": "ak_ewr4dsWehiwAT", diff --git a/src/services/DevStore.Billing.API/appsettings.Docker.json b/src/services/DevStore.Billing.API/appsettings.Docker.json index a0ab141..04393e4 100644 --- a/src/services/DevStore.Billing.API/appsettings.Docker.json +++ b/src/services/DevStore.Billing.API/appsettings.Docker.json @@ -7,7 +7,7 @@ } }, "ConnectionStrings": { - "DefaultConnection": "Server=sql-server;Database=DSBilling;MultipleActiveResultSets=true;User Id=sa;Password=MyDB@123" + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=DSBilling;MultipleActiveResultSets=true" }, "MessageQueueConnection": { "MessageBus": "host=devstore-rabbit:5672;publisherConfirms=true;timeout=30;username=devstore;password=devstore" diff --git a/src/services/DevStore.Identity.API/Configuration/IdentityConfig.cs b/src/services/DevStore.Identity.API/Configuration/IdentityConfig.cs index 8547537dd0a7eddfa81e041394969f6690607b10..3e65afea115d56782f90cebf51bd07580ea07e4b 100644 GIT binary patch delta 314 zcmX>nxkYM1h^q@jDnl7VFhdDLK0^_Zt;Y}!B$F5%83GtQfjnopxC=ufP*oyOE|H-a zsK$*U2goV|$xn1FogBd^vRRB#iE-isp44Kn!V-o|hGYf>2C7&AbV>lwf%!lSGZ|8V z))!4a$SghCfRSyp1=Bai$zqHG;;HCLfNli3Zn8Oxtu)9HB|w}EB++~_c_WMLW(8I) kMp+%8Yn6arF95<|um+GH@)**A9#)z>kyU?l1zQ*!0K!#5N&o-= delta 220 zcmdlYbxv|Z$Yei8k%e2wWFXGb7;G8rfF!D@9z!TlE|npep^za5NTvdfEd!Gp49Sxd zStJAX7~FyU5(bc!c|e%TkPJ697|1FD+K|VP&Y;1d#NYyyO=C!8C