From 78af81bf1ca80defdb4b090da43a072f74a4bc7f Mon Sep 17 00:00:00 2001 From: Maksim Lioshyn Date: Wed, 4 Jan 2023 14:56:13 +0400 Subject: [PATCH] Task 1 done --- deploy/k8s/helm-simple/apigateway/Chart.yaml | 21 ++ .../apigateway/templates/ingress-gateway.yaml | 144 +++++++++++ .../helm-simple/backgroundtasks/Chart.yaml | 21 ++ .../backgroundtasks/templates/configmap.yaml | 18 ++ .../backgroundtasks/templates/deployment.yaml | 42 ++++ .../backgroundtasks/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/basket/Chart.yaml | 21 ++ .../basket/templates/configmap.yaml | 16 ++ .../basket/templates/deployment.yaml | 45 ++++ .../helm-simple/basket/templates/ingress.yaml | 20 ++ .../helm-simple/basket/templates/service.yaml | 17 ++ deploy/k8s/helm-simple/basketdata/Chart.yaml | 21 ++ .../basketdata/templates/deployment.yaml | 25 ++ .../basketdata/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/catalog/Chart.yaml | 21 ++ .../catalog/templates/configmap.yaml | 19 ++ .../catalog/templates/deployment.yaml | 43 ++++ .../catalog/templates/ingress.yaml | 20 ++ .../catalog/templates/service.yaml | 17 ++ deploy/k8s/helm-simple/coupon/Chart.yaml | 21 ++ .../coupon/templates/configmap.yaml | 19 ++ .../coupon/templates/deployment.yaml | 43 ++++ .../helm-simple/coupon/templates/ingress.yaml | 20 ++ .../helm-simple/coupon/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/identity/Chart.yaml | 21 ++ .../identity/templates/configmap.yaml | 21 ++ .../identity/templates/deployment.yaml | 42 ++++ .../identity/templates/ingress.yaml | 20 ++ .../identity/templates/service.yaml | 13 + deploy/k8s/helm-simple/nosqldata/Chart.yaml | 21 ++ .../nosqldata/templates/deployment.yaml | 25 ++ .../nosqldata/templates/service.yaml | 13 + deploy/k8s/helm-simple/ordering/Chart.yaml | 21 ++ .../ordering/templates/configmap.yaml | 23 ++ .../ordering/templates/deployment.yaml | 45 ++++ .../ordering/templates/ingress.yaml | 20 ++ .../ordering/templates/service.yaml | 17 ++ deploy/k8s/helm-simple/payment/Chart.yaml | 21 ++ .../payment/templates/configmap.yaml | 16 ++ .../payment/templates/deployment.yaml | 45 ++++ .../payment/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/rabbitmq/Chart.yaml | 21 ++ .../rabbitmq/templates/deployment.yaml | 28 +++ .../rabbitmq/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/seq/Chart.yaml | 21 ++ .../helm-simple/seq/templates/deployment.yaml | 28 +++ .../helm-simple/seq/templates/ingress.yaml | 22 ++ .../helm-simple/seq/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/signalr/Chart.yaml | 21 ++ .../signalr/templates/configmap.yaml | 17 ++ .../signalr/templates/deployment.yaml | 42 ++++ .../signalr/templates/service.yaml | 14 ++ deploy/k8s/helm-simple/sqldata/Chart.yaml | 21 ++ .../sqldata/templates/deployment.yaml | 30 +++ .../sqldata/templates/service.yaml | 13 + .../k8s/helm-simple/webshoppingagg/Chart.yaml | 21 ++ .../webshoppingagg/templates/configmap.yaml | 25 ++ .../webshoppingagg/templates/deployment.yaml | 42 ++++ .../webshoppingagg/templates/service.yaml | 17 ++ deploy/k8s/helm-simple/webspa/Chart.yaml | 21 ++ .../webspa/templates/configmap.yaml | 24 ++ .../webspa/templates/deployment.yaml | 29 +++ .../helm-simple/webspa/templates/ingress.yaml | 20 ++ .../helm-simple/webspa/templates/service.yaml | 15 ++ deploy/k8s/helm-simple/webstatus/Chart.yaml | 21 ++ .../webstatus/templates/configmap.yaml | 32 +++ .../webstatus/templates/deployment.yaml | 29 +++ .../webstatus/templates/ingress.yaml | 20 ++ .../webstatus/templates/service.yaml | 14 ++ deploy/k8s/implementation-script.sh | 166 +++++++++++++ .../Envoy/config/webshopping/envoy.yaml | 21 ++ src/Services/Basket/Basket.API/Dockerfile | 1 + src/Services/Catalog/Catalog.API/Dockerfile | 1 + .../Controllers/CouponController.cs | 45 ++++ .../Coupon/Coupon.API/Coupon.API.csproj | 40 +++ .../Coupon/Coupon.API/CouponSettings.cs | 15 ++ src/Services/Coupon/Coupon.API/Dockerfile | 59 +++++ .../Coupon/Coupon.API/Dtos/CouponDto.cs | 9 + .../Coupon/Coupon.API/Dtos/IMapper.cs | 7 + src/Services/Coupon/Coupon.API/Dtos/Mapper.cs | 16 ++ .../Extensions/IHostBuilderExtensions.cs | 49 ++++ .../IServiceCollectionExtensions.cs | 227 ++++++++++++++++++ .../Filters/AuthorizeCheckOperationFilter.cs | 35 +++ .../Filters/ValidateModelAttribute.cs | 16 ++ .../Coupon.API/Infrastructure/CouponSeed.cs | 52 ++++ .../Infrastructure/Models/Coupon.cs | 20 ++ .../Repositories/CouponContext.cs | 25 ++ .../Repositories/CouponRepository.cs | 42 ++++ .../Repositories/ICouponRepository.cs | 14 ++ ...CouponValidationIntegrationEventHandler.cs | 56 +++++ ...angedToCancelledIntegrationEventHandler.cs | 22 ++ .../OrderCouponConfirmedIntegrationEvent.cs | 17 ++ .../OrderCouponRejectedIntegrationEvent.cs | 17 ++ ...waitingCouponValidationIntegrationEvent.cs | 20 ++ ...tatusChangedToCancelledIntegrationEvent.cs | 20 ++ src/Services/Coupon/Coupon.API/Program.cs | 53 ++++ .../Coupon.API/Properties/launchSettings.json | 12 + src/Services/Coupon/Coupon.API/Startup.cs | 95 ++++++++ .../Coupon.API/appsettings.Development.json | 18 ++ .../Coupon/Coupon.API/appsettings.json | 28 +++ src/Services/Identity/Identity.API/Dockerfile | 1 + src/Services/Ordering/Ordering.API/Dockerfile | 1 + .../Ordering.BackgroundTasks/Dockerfile | 1 + .../Ordering/Ordering.SignalrHub/Dockerfile | 1 + src/Services/Payment/Payment.API/Dockerfile | 1 + src/Services/Webhooks/Webhooks.API/Dockerfile | 1 + src/Web/WebMVC/Dockerfile | 1 + .../orders-detail.component.html | 9 + .../orders-new/orders-new.component.html | 32 +++ src/Web/WebSPA/Dockerfile | 1 + src/Web/WebStatus/Dockerfile | 1 + src/Web/WebhookClient/Dockerfile | 1 + src/docker-compose.override.yml | 25 ++ src/docker-compose.yml | 14 ++ src/eShopOnContainers-ServicesAndWebApps.sln | 62 ++++- 115 files changed, 3076 insertions(+), 4 deletions(-) create mode 100644 deploy/k8s/helm-simple/apigateway/Chart.yaml create mode 100644 deploy/k8s/helm-simple/apigateway/templates/ingress-gateway.yaml create mode 100644 deploy/k8s/helm-simple/backgroundtasks/Chart.yaml create mode 100644 deploy/k8s/helm-simple/backgroundtasks/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/backgroundtasks/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/backgroundtasks/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/basket/Chart.yaml create mode 100644 deploy/k8s/helm-simple/basket/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/basket/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/basket/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/basket/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/basketdata/Chart.yaml create mode 100644 deploy/k8s/helm-simple/basketdata/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/basketdata/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/catalog/Chart.yaml create mode 100644 deploy/k8s/helm-simple/catalog/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/catalog/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/catalog/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/catalog/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/coupon/Chart.yaml create mode 100644 deploy/k8s/helm-simple/coupon/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/coupon/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/coupon/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/coupon/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/identity/Chart.yaml create mode 100644 deploy/k8s/helm-simple/identity/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/identity/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/identity/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/identity/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/nosqldata/Chart.yaml create mode 100644 deploy/k8s/helm-simple/nosqldata/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/nosqldata/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/ordering/Chart.yaml create mode 100644 deploy/k8s/helm-simple/ordering/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/ordering/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/ordering/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/ordering/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/payment/Chart.yaml create mode 100644 deploy/k8s/helm-simple/payment/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/payment/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/payment/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/rabbitmq/Chart.yaml create mode 100644 deploy/k8s/helm-simple/rabbitmq/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/rabbitmq/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/seq/Chart.yaml create mode 100644 deploy/k8s/helm-simple/seq/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/seq/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/seq/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/signalr/Chart.yaml create mode 100644 deploy/k8s/helm-simple/signalr/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/signalr/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/signalr/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/sqldata/Chart.yaml create mode 100644 deploy/k8s/helm-simple/sqldata/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/sqldata/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/webshoppingagg/Chart.yaml create mode 100644 deploy/k8s/helm-simple/webshoppingagg/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/webshoppingagg/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/webshoppingagg/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/webspa/Chart.yaml create mode 100644 deploy/k8s/helm-simple/webspa/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/webspa/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/webspa/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/webspa/templates/service.yaml create mode 100644 deploy/k8s/helm-simple/webstatus/Chart.yaml create mode 100644 deploy/k8s/helm-simple/webstatus/templates/configmap.yaml create mode 100644 deploy/k8s/helm-simple/webstatus/templates/deployment.yaml create mode 100644 deploy/k8s/helm-simple/webstatus/templates/ingress.yaml create mode 100644 deploy/k8s/helm-simple/webstatus/templates/service.yaml create mode 100644 deploy/k8s/implementation-script.sh create mode 100644 src/Services/Coupon/Coupon.API/Controllers/CouponController.cs create mode 100644 src/Services/Coupon/Coupon.API/Coupon.API.csproj create mode 100644 src/Services/Coupon/Coupon.API/CouponSettings.cs create mode 100644 src/Services/Coupon/Coupon.API/Dockerfile create mode 100644 src/Services/Coupon/Coupon.API/Dtos/CouponDto.cs create mode 100644 src/Services/Coupon/Coupon.API/Dtos/IMapper.cs create mode 100644 src/Services/Coupon/Coupon.API/Dtos/Mapper.cs create mode 100644 src/Services/Coupon/Coupon.API/Extensions/IHostBuilderExtensions.cs create mode 100644 src/Services/Coupon/Coupon.API/Extensions/IServiceCollectionExtensions.cs create mode 100644 src/Services/Coupon/Coupon.API/Filters/AuthorizeCheckOperationFilter.cs create mode 100644 src/Services/Coupon/Coupon.API/Filters/ValidateModelAttribute.cs create mode 100644 src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs create mode 100644 src/Services/Coupon/Coupon.API/Infrastructure/Models/Coupon.cs create mode 100644 src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponContext.cs create mode 100644 src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponRepository.cs create mode 100644 src/Services/Coupon/Coupon.API/Infrastructure/Repositories/ICouponRepository.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToCancelledIntegrationEventHandler.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponConfirmedIntegrationEvent.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponRejectedIntegrationEvent.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToAwaitingCouponValidationIntegrationEvent.cs create mode 100644 src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs create mode 100644 src/Services/Coupon/Coupon.API/Program.cs create mode 100644 src/Services/Coupon/Coupon.API/Properties/launchSettings.json create mode 100644 src/Services/Coupon/Coupon.API/Startup.cs create mode 100644 src/Services/Coupon/Coupon.API/appsettings.Development.json create mode 100644 src/Services/Coupon/Coupon.API/appsettings.json diff --git a/deploy/k8s/helm-simple/apigateway/Chart.yaml b/deploy/k8s/helm-simple/apigateway/Chart.yaml new file mode 100644 index 000000000..3ee0e09a9 --- /dev/null +++ b/deploy/k8s/helm-simple/apigateway/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: apigateway +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/apigateway/templates/ingress-gateway.yaml b/deploy/k8s/helm-simple/apigateway/templates/ingress-gateway.yaml new file mode 100644 index 000000000..337379d5e --- /dev/null +++ b/deploy/k8s/helm-simple/apigateway/templates/ingress-gateway.yaml @@ -0,0 +1,144 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-c + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /catalog-api/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway/c(/|$)(.*) + pathType: Prefix + backend: + service: + name: catalog-api + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-b + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /basket-api/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway/b(/|$)(.*) + pathType: Prefix + backend: + service: + name: basket-api + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-o + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /ordering-api/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway/o(/|$)(.*) + pathType: Prefix + backend: + service: + name: ordering-api + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-cp + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /coupon-api/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway/cp(/|$)(.*) + pathType: Prefix + backend: + service: + name: coupon-api + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-agg + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /webshoppingagg/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway(/|$)(.*) + pathType: Prefix + backend: + service: + name: webshoppingagg + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-gw-signalr + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /hub/notificationhub/$2 + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + nginx.org/websocket-services: "ordering-signalrhub" + labels: + app: eshop +spec: + rules: + - http: + paths: + - path: /apigateway/hub/notificationhub(/|$)(.*) + pathType: Prefix + backend: + service: + name: ordering-signalrhub + port: + number: 80 diff --git a/deploy/k8s/helm-simple/backgroundtasks/Chart.yaml b/deploy/k8s/helm-simple/backgroundtasks/Chart.yaml new file mode 100644 index 000000000..32a5ab4d3 --- /dev/null +++ b/deploy/k8s/helm-simple/backgroundtasks/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: backgroundtasks +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/backgroundtasks/templates/configmap.yaml b/deploy/k8s/helm-simple/backgroundtasks/templates/configmap.yaml new file mode 100644 index 000000000..4b5ad0225 --- /dev/null +++ b/deploy/k8s/helm-simple/backgroundtasks/templates/configmap.yaml @@ -0,0 +1,18 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: backgroundtasks-cm + labels: + app: eshop + service: backgroundtasks +data: + OrchestratorType: K8S + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + EventBusConnection: rabbitmq + AzureServiceBusEnabled: "False" + ConnectionString: Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word + UseCustomizationData: "True" + CheckUpdateTime: "15000" + GracePeriodTime: "15" + Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ: Verbose diff --git a/deploy/k8s/helm-simple/backgroundtasks/templates/deployment.yaml b/deploy/k8s/helm-simple/backgroundtasks/templates/deployment.yaml new file mode 100644 index 000000000..3077e4549 --- /dev/null +++ b/deploy/k8s/helm-simple/backgroundtasks/templates/deployment.yaml @@ -0,0 +1,42 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: backgroundtasks + labels: + app: eshop + service: backgroundtasks +spec: + replicas: 1 + selector: + matchLabels: + service: backgroundtasks + template: + metadata: + labels: + app: eshop + service: backgroundtasks + spec: + containers: + - name: ordering-backgroundtasks + image: {{ .Values.registry }}/ordering.backgroundtasks:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: backgroundtasks-cm diff --git a/deploy/k8s/helm-simple/backgroundtasks/templates/service.yaml b/deploy/k8s/helm-simple/backgroundtasks/templates/service.yaml new file mode 100644 index 000000000..624e2a697 --- /dev/null +++ b/deploy/k8s/helm-simple/backgroundtasks/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: ordering-backgroundtasks + labels: + app: eshop + service: backgroundtasks +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: backgroundtasks diff --git a/deploy/k8s/helm-simple/basket/Chart.yaml b/deploy/k8s/helm-simple/basket/Chart.yaml new file mode 100644 index 000000000..1448246e3 --- /dev/null +++ b/deploy/k8s/helm-simple/basket/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: basket +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/basket/templates/configmap.yaml b/deploy/k8s/helm-simple/basket/templates/configmap.yaml new file mode 100644 index 000000000..9506c44c4 --- /dev/null +++ b/deploy/k8s/helm-simple/basket/templates/configmap.yaml @@ -0,0 +1,16 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: basket-cm + labels: + app: eshop + service: basket +data: + ASPNETCORE_ENVIRONMENT: Development + AzureServiceBusEnabled: "False" + ConnectionString: basketdata + EventBusConnection: rabbitmq + identityUrl: http://identity-api + IdentityUrlExternal: http://{{ .Values.aksLB }}/identity + OrchestratorType: K8S + PATH_BASE: /basket-api \ No newline at end of file diff --git a/deploy/k8s/helm-simple/basket/templates/deployment.yaml b/deploy/k8s/helm-simple/basket/templates/deployment.yaml new file mode 100644 index 000000000..3baae5ea1 --- /dev/null +++ b/deploy/k8s/helm-simple/basket/templates/deployment.yaml @@ -0,0 +1,45 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: basket + labels: + app: eshop + service: basket +spec: + replicas: 1 + selector: + matchLabels: + service: basket + template: + metadata: + labels: + app: eshop + service: basket + spec: + containers: + - name: basket-api + image: {{ .Values.registry }}/basket.api:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: basket-cm diff --git a/deploy/k8s/helm-simple/basket/templates/ingress.yaml b/deploy/k8s/helm-simple/basket/templates/ingress.yaml new file mode 100644 index 000000000..895e696bf --- /dev/null +++ b/deploy/k8s/helm-simple/basket/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: basket + labels: + app: eshop + service: basket + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /basket-api + pathType: Prefix + backend: + service: + name: basket-api + port: + number: 80 diff --git a/deploy/k8s/helm-simple/basket/templates/service.yaml b/deploy/k8s/helm-simple/basket/templates/service.yaml new file mode 100644 index 000000000..035b19188 --- /dev/null +++ b/deploy/k8s/helm-simple/basket/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: basket-api + labels: + app: eshop + service: basket +spec: + ports: + - port: 80 + protocol: TCP + name: http + - port: 81 + protocol: TCP + name: grpc + selector: + service: basket diff --git a/deploy/k8s/helm-simple/basketdata/Chart.yaml b/deploy/k8s/helm-simple/basketdata/Chart.yaml new file mode 100644 index 000000000..652e334b3 --- /dev/null +++ b/deploy/k8s/helm-simple/basketdata/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: basketdata +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/basketdata/templates/deployment.yaml b/deploy/k8s/helm-simple/basketdata/templates/deployment.yaml new file mode 100644 index 000000000..32f3c19c3 --- /dev/null +++ b/deploy/k8s/helm-simple/basketdata/templates/deployment.yaml @@ -0,0 +1,25 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: basketdata + labels: + app: eshop + service: basketdata +spec: + replicas: 1 + selector: + matchLabels: + service: basketdata + template: + metadata: + labels: + app: eshop + service: basketdata + spec: + containers: + - name: basketdata + image: redis:alpine + ports: + - name: redis + containerPort: 6379 + protocol: TCP diff --git a/deploy/k8s/helm-simple/basketdata/templates/service.yaml b/deploy/k8s/helm-simple/basketdata/templates/service.yaml new file mode 100644 index 000000000..39fe736ee --- /dev/null +++ b/deploy/k8s/helm-simple/basketdata/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: basketdata + labels: + app: eshop + service: basketdata +spec: + ports: + - port: 6379 + protocol: TCP + name: redis + selector: + service: basketdata diff --git a/deploy/k8s/helm-simple/catalog/Chart.yaml b/deploy/k8s/helm-simple/catalog/Chart.yaml new file mode 100644 index 000000000..02e4104dd --- /dev/null +++ b/deploy/k8s/helm-simple/catalog/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: catalog +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/catalog/templates/configmap.yaml b/deploy/k8s/helm-simple/catalog/templates/configmap.yaml new file mode 100644 index 000000000..9faa5bb50 --- /dev/null +++ b/deploy/k8s/helm-simple/catalog/templates/configmap.yaml @@ -0,0 +1,19 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: catalog-cm + labels: + app: eshop + service: catalog +data: + ASPNETCORE_ENVIRONMENT: Development + AzureServiceBusEnabled: "False" + AzureStorageEnabled: "False" + ConnectionString: Server=sqldata;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word + EventBusConnection: rabbitmq + GRPC_PORT: "81" + OrchestratorType: K8S + PATH_BASE: /catalog-api + PicBaseUrl: http://{{ .Values.aksLB }}/apigateway/c/api/v1/catalog/items/[0]/pic/ + PORT: "80" + UseCustomizationData: "False" diff --git a/deploy/k8s/helm-simple/catalog/templates/deployment.yaml b/deploy/k8s/helm-simple/catalog/templates/deployment.yaml new file mode 100644 index 000000000..d3bdc45e2 --- /dev/null +++ b/deploy/k8s/helm-simple/catalog/templates/deployment.yaml @@ -0,0 +1,43 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: catalog + labels: + app: eshop + service: catalog +spec: + replicas: 1 + selector: + matchLabels: + service: catalog + template: + metadata: + labels: + app: eshop + service: catalog + spec: + containers: + - name: catalog-api + image: {{ .Values.registry }}/catalog.api:linux-net6-initial + imagePullPolicy: Always + ports: + - containerPort: 80 + protocol: TCP + - containerPort: 81 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: catalog-cm diff --git a/deploy/k8s/helm-simple/catalog/templates/ingress.yaml b/deploy/k8s/helm-simple/catalog/templates/ingress.yaml new file mode 100644 index 000000000..f6ca35fb4 --- /dev/null +++ b/deploy/k8s/helm-simple/catalog/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: catalog + labels: + app: eshop + service: catalog + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /catalog-api + pathType: Prefix + backend: + service: + name: catalog-api + port: + number: 80 diff --git a/deploy/k8s/helm-simple/catalog/templates/service.yaml b/deploy/k8s/helm-simple/catalog/templates/service.yaml new file mode 100644 index 000000000..10d981600 --- /dev/null +++ b/deploy/k8s/helm-simple/catalog/templates/service.yaml @@ -0,0 +1,17 @@ +kind: Service +apiVersion: v1 +metadata: + name: catalog-api + labels: + app: eshop + service: catalog +spec: + ports: + - port: 80 + protocol: TCP + name: http + - port: 81 + protocol: TCP + name: grpc + selector: + service: catalog diff --git a/deploy/k8s/helm-simple/coupon/Chart.yaml b/deploy/k8s/helm-simple/coupon/Chart.yaml new file mode 100644 index 000000000..9f338f681 --- /dev/null +++ b/deploy/k8s/helm-simple/coupon/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: coupon +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/coupon/templates/configmap.yaml b/deploy/k8s/helm-simple/coupon/templates/configmap.yaml new file mode 100644 index 000000000..d6ff350b6 --- /dev/null +++ b/deploy/k8s/helm-simple/coupon/templates/configmap.yaml @@ -0,0 +1,19 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: coupon-cm + labels: + app: eshop + service: coupon +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + AzureServiceBusEnabled: "False" + CheckUpdateTime: "30000" + ConnectionString: mongodb://nosqldata + EventBusConnection: rabbitmq + identityUrl: http://identity-api + OrchestratorType: K8S + PATH_BASE: /coupon-api + Serilog__MinimumLevel__Override__coupon-api: Verbose + Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ: Verbose diff --git a/deploy/k8s/helm-simple/coupon/templates/deployment.yaml b/deploy/k8s/helm-simple/coupon/templates/deployment.yaml new file mode 100644 index 000000000..5edf474f9 --- /dev/null +++ b/deploy/k8s/helm-simple/coupon/templates/deployment.yaml @@ -0,0 +1,43 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: coupon + labels: + app: eshop + service: coupon +spec: + replicas: 1 + selector: + matchLabels: + service: coupon + template: + metadata: + labels: + app: eshop + service: coupon + spec: + containers: + - name: coupon-api + image: {{ .Values.registry }}/coupon.api:linux-net6-initial + imagePullPolicy: Always + ports: + - containerPort: 80 + protocol: TCP + - containerPort: 81 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: coupon-cm diff --git a/deploy/k8s/helm-simple/coupon/templates/ingress.yaml b/deploy/k8s/helm-simple/coupon/templates/ingress.yaml new file mode 100644 index 000000000..4a35bddf6 --- /dev/null +++ b/deploy/k8s/helm-simple/coupon/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: coupon + labels: + app: eshop + service: coupon + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /coupon-api + pathType: Prefix + backend: + service: + name: coupon-api + port: + number: 80 diff --git a/deploy/k8s/helm-simple/coupon/templates/service.yaml b/deploy/k8s/helm-simple/coupon/templates/service.yaml new file mode 100644 index 000000000..7e6fee6c2 --- /dev/null +++ b/deploy/k8s/helm-simple/coupon/templates/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: coupon-api + labels: + app: eshop + service: coupon +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: coupon diff --git a/deploy/k8s/helm-simple/identity/Chart.yaml b/deploy/k8s/helm-simple/identity/Chart.yaml new file mode 100644 index 000000000..404c8d7ae --- /dev/null +++ b/deploy/k8s/helm-simple/identity/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: identity +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/identity/templates/configmap.yaml b/deploy/k8s/helm-simple/identity/templates/configmap.yaml new file mode 100644 index 000000000..3cb508ca8 --- /dev/null +++ b/deploy/k8s/helm-simple/identity/templates/configmap.yaml @@ -0,0 +1,21 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: identity-cm + labels: + app: eshop + service: identity +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + BasketApiClient: http://{{ .Values.aksLB }}/basket-api + ConnectionString: Server=sqldata;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word + CouponApiClient: http://{{ .Values.aksLB }}/coupon-api + DPConnectionString: basketdata + IsClusterEnv: "True" + OrchestratorType: K8S + OrderingApiClient: http://{{ .Values.aksLB }}/ordering-api + PATH_BASE: /identity + SpaClient: http://{{ .Values.aksLB }} + UseCustomizationData: "True" + WebShoppingAggClient: http://{{ .Values.aksLB }}/webshoppingagg diff --git a/deploy/k8s/helm-simple/identity/templates/deployment.yaml b/deploy/k8s/helm-simple/identity/templates/deployment.yaml new file mode 100644 index 000000000..31e04c07f --- /dev/null +++ b/deploy/k8s/helm-simple/identity/templates/deployment.yaml @@ -0,0 +1,42 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: identity + labels: + app: eshop + service: identity +spec: + replicas: 1 + selector: + matchLabels: + service: identity + template: + metadata: + labels: + app: eshop + service: identity + spec: + containers: + - name: identity-api + image: {{ .Values.registry }}/identity.api:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: identity-cm diff --git a/deploy/k8s/helm-simple/identity/templates/ingress.yaml b/deploy/k8s/helm-simple/identity/templates/ingress.yaml new file mode 100644 index 000000000..2739f7081 --- /dev/null +++ b/deploy/k8s/helm-simple/identity/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: identity + labels: + app: eshop + service: identity + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /identity + pathType: Prefix + backend: + service: + name: identity-api + port: + number: 80 diff --git a/deploy/k8s/helm-simple/identity/templates/service.yaml b/deploy/k8s/helm-simple/identity/templates/service.yaml new file mode 100644 index 000000000..f7d4428f0 --- /dev/null +++ b/deploy/k8s/helm-simple/identity/templates/service.yaml @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + name: identity-api + labels: + app: eshop + service: identity +spec: + ports: + - port: 80 + protocol: TCP + selector: + service: identity diff --git a/deploy/k8s/helm-simple/nosqldata/Chart.yaml b/deploy/k8s/helm-simple/nosqldata/Chart.yaml new file mode 100644 index 000000000..71d8ba458 --- /dev/null +++ b/deploy/k8s/helm-simple/nosqldata/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: nosqldata +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/nosqldata/templates/deployment.yaml b/deploy/k8s/helm-simple/nosqldata/templates/deployment.yaml new file mode 100644 index 000000000..7478dfb96 --- /dev/null +++ b/deploy/k8s/helm-simple/nosqldata/templates/deployment.yaml @@ -0,0 +1,25 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: nosqldata + labels: + app: eshop + service: nosqldata +spec: + replicas: 1 + selector: + matchLabels: + service: nosqldata + template: + metadata: + labels: + app: eshop + service: nosqldata + spec: + containers: + - name: nosqldata + image: mongo + ports: + - name: mongodb + containerPort: 27017 + protocol: TCP diff --git a/deploy/k8s/helm-simple/nosqldata/templates/service.yaml b/deploy/k8s/helm-simple/nosqldata/templates/service.yaml new file mode 100644 index 000000000..02da38a2d --- /dev/null +++ b/deploy/k8s/helm-simple/nosqldata/templates/service.yaml @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + name: nosqldata + labels: + app: eshop + service: nosqldata +spec: + ports: + - port: 27017 + protocol: TCP + selector: + service: nosqldata diff --git a/deploy/k8s/helm-simple/ordering/Chart.yaml b/deploy/k8s/helm-simple/ordering/Chart.yaml new file mode 100644 index 000000000..4b97afc3b --- /dev/null +++ b/deploy/k8s/helm-simple/ordering/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: ordering +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/ordering/templates/configmap.yaml b/deploy/k8s/helm-simple/ordering/templates/configmap.yaml new file mode 100644 index 000000000..0945ece60 --- /dev/null +++ b/deploy/k8s/helm-simple/ordering/templates/configmap.yaml @@ -0,0 +1,23 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: ordering-cm + labels: + app: eshop + service: ordering +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + AzureServiceBusEnabled: "False" + CheckUpdateTime: "30000" + ConnectionString: Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word + EventBusConnection: rabbitmq + GRPC_PORT: "81" + identityUrl: http://identity-api + IdentityUrlExternal: http://{{ .Values.aksLB }}/identity + OrchestratorType: K8S + PATH_BASE: /ordering-api + PORT: "80" + Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ: Verbose + Serilog__MinimumLevel__Override__ordering.api: Verbose + UseCustomizationData: "True" diff --git a/deploy/k8s/helm-simple/ordering/templates/deployment.yaml b/deploy/k8s/helm-simple/ordering/templates/deployment.yaml new file mode 100644 index 000000000..7d94a0d48 --- /dev/null +++ b/deploy/k8s/helm-simple/ordering/templates/deployment.yaml @@ -0,0 +1,45 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: ordering + labels: + app: eshop + service: ordering +spec: + replicas: 1 + selector: + matchLabels: + service: ordering + template: + metadata: + labels: + app: eshop + service: ordering + spec: + containers: + - name: ordering-api + image: {{ .Values.registry }}/ordering.api:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: ordering-cm diff --git a/deploy/k8s/helm-simple/ordering/templates/ingress.yaml b/deploy/k8s/helm-simple/ordering/templates/ingress.yaml new file mode 100644 index 000000000..67d393871 --- /dev/null +++ b/deploy/k8s/helm-simple/ordering/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: ordering + labels: + app: eshop + service: ordering + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /ordering-api + pathType: Prefix + backend: + service: + name: ordering-api + port: + number: 80 diff --git a/deploy/k8s/helm-simple/ordering/templates/service.yaml b/deploy/k8s/helm-simple/ordering/templates/service.yaml new file mode 100644 index 000000000..9291a622d --- /dev/null +++ b/deploy/k8s/helm-simple/ordering/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: ordering-api + labels: + app: eshop + service: ordering +spec: + ports: + - port: 80 + protocol: TCP + name: http + - port: 81 + protocol: TCP + name: grpc + selector: + service: ordering diff --git a/deploy/k8s/helm-simple/payment/Chart.yaml b/deploy/k8s/helm-simple/payment/Chart.yaml new file mode 100644 index 000000000..2762389be --- /dev/null +++ b/deploy/k8s/helm-simple/payment/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: payment +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/payment/templates/configmap.yaml b/deploy/k8s/helm-simple/payment/templates/configmap.yaml new file mode 100644 index 000000000..19520fdd9 --- /dev/null +++ b/deploy/k8s/helm-simple/payment/templates/configmap.yaml @@ -0,0 +1,16 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: payment-cm + labels: + app: eshop + service: payment +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + AzureServiceBusEnabled: "False" + EventBusConnection: rabbitmq + MaxOrderTotal: "100" + OrchestratorType: K8S + Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ: Verbose + Serilog__MinimumLevel__Override__payment-api.IntegrationEvents.EventHandling: "Verbose" diff --git a/deploy/k8s/helm-simple/payment/templates/deployment.yaml b/deploy/k8s/helm-simple/payment/templates/deployment.yaml new file mode 100644 index 000000000..d8c31d0a9 --- /dev/null +++ b/deploy/k8s/helm-simple/payment/templates/deployment.yaml @@ -0,0 +1,45 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: payment + labels: + app: eshop + service: payment +spec: + replicas: 1 + selector: + matchLabels: + service: payment + template: + metadata: + labels: + app: eshop + service: payment + spec: + containers: + - name: payment-api + image: {{ .Values.registry }}/payment.api:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: payment-cm diff --git a/deploy/k8s/helm-simple/payment/templates/service.yaml b/deploy/k8s/helm-simple/payment/templates/service.yaml new file mode 100644 index 000000000..664b388da --- /dev/null +++ b/deploy/k8s/helm-simple/payment/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: payment-api + labels: + app: eshop + service: payment +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: payment diff --git a/deploy/k8s/helm-simple/rabbitmq/Chart.yaml b/deploy/k8s/helm-simple/rabbitmq/Chart.yaml new file mode 100644 index 000000000..65f760e0c --- /dev/null +++ b/deploy/k8s/helm-simple/rabbitmq/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: rabbitmq +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/rabbitmq/templates/deployment.yaml b/deploy/k8s/helm-simple/rabbitmq/templates/deployment.yaml new file mode 100644 index 000000000..2fd6ea5d9 --- /dev/null +++ b/deploy/k8s/helm-simple/rabbitmq/templates/deployment.yaml @@ -0,0 +1,28 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: rabbitmq + labels: + app: eshop + service: rabbitmq +spec: + replicas: 1 + selector: + matchLabels: + service: rabbitmq + template: + metadata: + labels: + app: eshop + service: rabbitmq + spec: + containers: + - name: rabbitmq + image: rabbitmq:3-management-alpine + ports: + - name: rabbitmq + containerPort: 5672 + protocol: TCP + - name: management + containerPort: 15672 + protocol: TCP diff --git a/deploy/k8s/helm-simple/rabbitmq/templates/service.yaml b/deploy/k8s/helm-simple/rabbitmq/templates/service.yaml new file mode 100644 index 000000000..f16bf911c --- /dev/null +++ b/deploy/k8s/helm-simple/rabbitmq/templates/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: rabbitmq + labels: + app: eshop + service: rabbitmq +spec: + ports: + - port: 5672 + protocol: TCP + name: rabbitmq + selector: + service: rabbitmq diff --git a/deploy/k8s/helm-simple/seq/Chart.yaml b/deploy/k8s/helm-simple/seq/Chart.yaml new file mode 100644 index 000000000..d84656742 --- /dev/null +++ b/deploy/k8s/helm-simple/seq/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: seq +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/seq/templates/deployment.yaml b/deploy/k8s/helm-simple/seq/templates/deployment.yaml new file mode 100644 index 000000000..0d5e55928 --- /dev/null +++ b/deploy/k8s/helm-simple/seq/templates/deployment.yaml @@ -0,0 +1,28 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: seq + labels: + app: eshop + service: seq +spec: + replicas: 1 + selector: + matchLabels: + service: seq + template: + metadata: + labels: + app: eshop + service: seq + spec: + containers: + - name: seq + image: datalust/seq:latest + ports: + - name: http + containerPort: 80 + protocol: TCP + env: + - name: ACCEPT_EULA + value: "Y" diff --git a/deploy/k8s/helm-simple/seq/templates/ingress.yaml b/deploy/k8s/helm-simple/seq/templates/ingress.yaml new file mode 100644 index 000000000..17bef385d --- /dev/null +++ b/deploy/k8s/helm-simple/seq/templates/ingress.yaml @@ -0,0 +1,22 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: seq + labels: + app: eshop + service: seq + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + rules: + - http: + paths: + - path: /seq(/|$)(.*) + pathType: Prefix + backend: + service: + name: seq + port: + number: 80 diff --git a/deploy/k8s/helm-simple/seq/templates/service.yaml b/deploy/k8s/helm-simple/seq/templates/service.yaml new file mode 100644 index 000000000..abe0b3a0d --- /dev/null +++ b/deploy/k8s/helm-simple/seq/templates/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: seq + labels: + app: eshop + service: seq +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: seq diff --git a/deploy/k8s/helm-simple/signalr/Chart.yaml b/deploy/k8s/helm-simple/signalr/Chart.yaml new file mode 100644 index 000000000..1abff0571 --- /dev/null +++ b/deploy/k8s/helm-simple/signalr/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: signalr +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/signalr/templates/configmap.yaml b/deploy/k8s/helm-simple/signalr/templates/configmap.yaml new file mode 100644 index 000000000..105a29ec3 --- /dev/null +++ b/deploy/k8s/helm-simple/signalr/templates/configmap.yaml @@ -0,0 +1,17 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: signalr-cm + labels: + app: eshop + service: signalr +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + AzureServiceBusEnabled: "False" + EventBusConnection: rabbitmq + identityUrl: http://identity-api + IsClusterEnv: "True" + OrchestratorType: K8S + PATH_BASE: /ordering-signalrhub + SignalrStoreConnectionString: basketdata diff --git a/deploy/k8s/helm-simple/signalr/templates/deployment.yaml b/deploy/k8s/helm-simple/signalr/templates/deployment.yaml new file mode 100644 index 000000000..efb46ea41 --- /dev/null +++ b/deploy/k8s/helm-simple/signalr/templates/deployment.yaml @@ -0,0 +1,42 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: signalr + labels: + app: eshop + service: signalr +spec: + replicas: 1 + selector: + matchLabels: + service: signalr + template: + metadata: + labels: + app: eshop + service: signalr + spec: + containers: + - name: ordering-signalrhub + image: {{ .Values.registry }}/ordering.signalrhub:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: signalr-cm diff --git a/deploy/k8s/helm-simple/signalr/templates/service.yaml b/deploy/k8s/helm-simple/signalr/templates/service.yaml new file mode 100644 index 000000000..0c8ce0fd7 --- /dev/null +++ b/deploy/k8s/helm-simple/signalr/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: ordering-signalrhub + labels: + app: eshop + service: signalr +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: signalr diff --git a/deploy/k8s/helm-simple/sqldata/Chart.yaml b/deploy/k8s/helm-simple/sqldata/Chart.yaml new file mode 100644 index 000000000..824b465f4 --- /dev/null +++ b/deploy/k8s/helm-simple/sqldata/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: sqldata +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/sqldata/templates/deployment.yaml b/deploy/k8s/helm-simple/sqldata/templates/deployment.yaml new file mode 100644 index 000000000..28ef0b184 --- /dev/null +++ b/deploy/k8s/helm-simple/sqldata/templates/deployment.yaml @@ -0,0 +1,30 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: sqldata + labels: + app: eshop + service: sqldata +spec: + replicas: 1 + selector: + matchLabels: + service: sqldata + template: + metadata: + labels: + app: eshop + service: sqldata + spec: + containers: + - name: sqldata + image: mcr.microsoft.com/mssql/server:2017-latest + ports: + - name: sqlserver + containerPort: 1433 + protocol: TCP + env: + - name: SA_PASSWORD + value: Pass@word + - name: ACCEPT_EULA + value: "Y" diff --git a/deploy/k8s/helm-simple/sqldata/templates/service.yaml b/deploy/k8s/helm-simple/sqldata/templates/service.yaml new file mode 100644 index 000000000..6ef34bed4 --- /dev/null +++ b/deploy/k8s/helm-simple/sqldata/templates/service.yaml @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + name: sqldata + labels: + app: eshop + service: sqldata +spec: + ports: + - port: 1433 + protocol: TCP + selector: + service: sqldata diff --git a/deploy/k8s/helm-simple/webshoppingagg/Chart.yaml b/deploy/k8s/helm-simple/webshoppingagg/Chart.yaml new file mode 100644 index 000000000..09eab2515 --- /dev/null +++ b/deploy/k8s/helm-simple/webshoppingagg/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: webshoppingagg +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/webshoppingagg/templates/configmap.yaml b/deploy/k8s/helm-simple/webshoppingagg/templates/configmap.yaml new file mode 100644 index 000000000..0e818e4c6 --- /dev/null +++ b/deploy/k8s/helm-simple/webshoppingagg/templates/configmap.yaml @@ -0,0 +1,25 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: webshoppingagg-cm + labels: + app: eshop + service: webshoppingagg +data: + ASPNETCORE_ENVIRONMENT: Development + BasketUrlHC: http://basket-api/hc + CatalogUrlHC: http://catalog-api/hc + CouponUrlHC: http://coupon-api/hc + IdentityUrlExternal: http://{{ .Values.aksLB }}/identity + IdentityUrlHC: http://identity-api/hc + OrderingUrlHC: http://ordering-api/hc + PATH_BASE: /webshoppingagg + PaymentUrlHC: http://payment-api/hc + urls__basket: http://basket-api + urls__catalog: http://catalog-api + urls__coupon: http://coupon-api + urls__grpcBasket: http://basket-api:81 + urls__grpcCatalog: http://catalog-api:81 + urls__grpcOrdering: http://ordering-api:81 + urls__identity: http://identity-api + urls__orders: http://ordering-api diff --git a/deploy/k8s/helm-simple/webshoppingagg/templates/deployment.yaml b/deploy/k8s/helm-simple/webshoppingagg/templates/deployment.yaml new file mode 100644 index 000000000..c0fdfeb2e --- /dev/null +++ b/deploy/k8s/helm-simple/webshoppingagg/templates/deployment.yaml @@ -0,0 +1,42 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: webshoppingagg + labels: + app: eshop + service: webshoppingagg +spec: + replicas: 1 + selector: + matchLabels: + service: webshoppingagg + template: + metadata: + labels: + app: eshop + service: webshoppingagg + spec: + containers: + - name: webshoppingagg + image: {{ .Values.registry }}/webshoppingagg:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + port: 80 + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + readinessProbe: + httpGet: + port: 80 + path: /hc + initialDelaySeconds: 90 + periodSeconds: 60 + timeoutSeconds: 5 + envFrom: + - configMapRef: + name: webshoppingagg-cm diff --git a/deploy/k8s/helm-simple/webshoppingagg/templates/service.yaml b/deploy/k8s/helm-simple/webshoppingagg/templates/service.yaml new file mode 100644 index 000000000..ce945fc38 --- /dev/null +++ b/deploy/k8s/helm-simple/webshoppingagg/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: webshoppingagg + labels: + app: eshop + service: webshoppingagg +spec: + ports: + - port: 80 + protocol: TCP + name: http + - port: 81 + protocol: TCP + name: grpc + selector: + service: webshoppingagg diff --git a/deploy/k8s/helm-simple/webspa/Chart.yaml b/deploy/k8s/helm-simple/webspa/Chart.yaml new file mode 100644 index 000000000..66d55ad6f --- /dev/null +++ b/deploy/k8s/helm-simple/webspa/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: webspa +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/webspa/templates/configmap.yaml b/deploy/k8s/helm-simple/webspa/templates/configmap.yaml new file mode 100644 index 000000000..ba8539fe1 --- /dev/null +++ b/deploy/k8s/helm-simple/webspa/templates/configmap.yaml @@ -0,0 +1,24 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: webspa-cm + labels: + app: eshop + service: webspa +data: + ASPNETCORE_ENVIRONMENT: Docker + ASPNETCORE_URLS: http://0.0.0.0:80 + CallBackUrl: http://{{ .Values.aksLB }} + DPConnectionString: basketdata + BasketUrl: http://{{ .Values.aksLB }}/apigateway + CallBackUrl: http://{{ .Values.aksLB }}/ + IdentityUrl: http://{{ .Values.aksLB }}/identity + IdentityUrlHC: http://identity-api/hc + IsClusterEnv: "True" + OrchestratorType: K8S + PATH_BASE: / + PurchaseUrl: http://{{ .Values.aksLB }}/apigateway + PurchaseUrlHC: http://ordering-api/hc + SignalrHubUrl: http://{{ .Values.aksLB }}/apigateway + UseCustomizationData: "True" + UseLoadTest: "False" diff --git a/deploy/k8s/helm-simple/webspa/templates/deployment.yaml b/deploy/k8s/helm-simple/webspa/templates/deployment.yaml new file mode 100644 index 000000000..e6a1c0600 --- /dev/null +++ b/deploy/k8s/helm-simple/webspa/templates/deployment.yaml @@ -0,0 +1,29 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: webspa + labels: + app: eshop + service: webspa +spec: + replicas: 1 + selector: + matchLabels: + service: webspa + template: + metadata: + labels: + app: eshop + service: webspa + spec: + containers: + - name: webspa + image: {{ .Values.registry }}/webspa:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + envFrom: + - configMapRef: + name: webspa-cm diff --git a/deploy/k8s/helm-simple/webspa/templates/ingress.yaml b/deploy/k8s/helm-simple/webspa/templates/ingress.yaml new file mode 100644 index 000000000..690c716fc --- /dev/null +++ b/deploy/k8s/helm-simple/webspa/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: webspa + labels: + app: eshop + service: webspa + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: webspa + port: + number: 80 diff --git a/deploy/k8s/helm-simple/webspa/templates/service.yaml b/deploy/k8s/helm-simple/webspa/templates/service.yaml new file mode 100644 index 000000000..c5b19ca3a --- /dev/null +++ b/deploy/k8s/helm-simple/webspa/templates/service.yaml @@ -0,0 +1,15 @@ +kind: Service +apiVersion: v1 +metadata: + name: webspa + labels: + app: eshop + service: webspa +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + service: webspa diff --git a/deploy/k8s/helm-simple/webstatus/Chart.yaml b/deploy/k8s/helm-simple/webstatus/Chart.yaml new file mode 100644 index 000000000..2c346e48e --- /dev/null +++ b/deploy/k8s/helm-simple/webstatus/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: webstatus +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0 diff --git a/deploy/k8s/helm-simple/webstatus/templates/configmap.yaml b/deploy/k8s/helm-simple/webstatus/templates/configmap.yaml new file mode 100644 index 000000000..0def0be44 --- /dev/null +++ b/deploy/k8s/helm-simple/webstatus/templates/configmap.yaml @@ -0,0 +1,32 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: webstatus-cm + labels: + app: eshop + service: webstatus +data: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://0.0.0.0:80 + HealthChecksUI__HealthChecks__0__Name: WebSPA HTTP Check + HealthChecksUI__HealthChecks__0__Uri: http://webspa/hc + HealthChecksUI__HealthChecks__1__Name: Web Shopping Aggregator GW HTTP Check + HealthChecksUI__HealthChecks__1__Uri: http://webshoppingagg/hc + HealthChecksUI__HealthChecks__2__Name: Ordering HTTP Check + HealthChecksUI__HealthChecks__2__Uri: http://ordering-api/hc + HealthChecksUI__HealthChecks__3__Name: Basket HTTP Check + HealthChecksUI__HealthChecks__3__Uri: http://basket-api/hc + HealthChecksUI__HealthChecks__4__Name: Catalog HTTP Check + HealthChecksUI__HealthChecks__4__Uri: http://catalog-api/hc + HealthChecksUI__HealthChecks__5__Name: Identity HTTP Check + HealthChecksUI__HealthChecks__5__Uri: http://identity-api/hc + HealthChecksUI__HealthChecks__6__Name: Payments HTTP Check + HealthChecksUI__HealthChecks__6__Uri: http://payment-api/hc + HealthChecksUI__HealthChecks__7__Name: Ordering SignalRHub HTTP Check + HealthChecksUI__HealthChecks__7__Uri: http://ordering-signalrhub/hc + HealthChecksUI__HealthChecks__8__Name: Ordering HTTP Background Check + HealthChecksUI__HealthChecks__8__Uri: http://ordering-backgroundtasks/hc + HealthChecksUI__HealthChecks__9__Name: Coupon HTTP Check + HealthChecksUI__HealthChecks__9__Uri: http://coupon-api/hc + OrchestratorType: K8S + PATH_BASE: /webstatus diff --git a/deploy/k8s/helm-simple/webstatus/templates/deployment.yaml b/deploy/k8s/helm-simple/webstatus/templates/deployment.yaml new file mode 100644 index 000000000..a2fae68b3 --- /dev/null +++ b/deploy/k8s/helm-simple/webstatus/templates/deployment.yaml @@ -0,0 +1,29 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: webstatus + labels: + app: eshop + service: webstatus +spec: + replicas: 1 + selector: + matchLabels: + service: webstatus + template: + metadata: + labels: + app: eshop + service: webstatus + spec: + containers: + - name: webstatus + image: {{ .Values.registry }}/webstatus:linux-net6-initial + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + protocol: TCP + envFrom: + - configMapRef: + name: webstatus-cm diff --git a/deploy/k8s/helm-simple/webstatus/templates/ingress.yaml b/deploy/k8s/helm-simple/webstatus/templates/ingress.yaml new file mode 100644 index 000000000..47d50e73d --- /dev/null +++ b/deploy/k8s/helm-simple/webstatus/templates/ingress.yaml @@ -0,0 +1,20 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: webstatus + labels: + app: eshop + service: webstatus + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + rules: + - http: + paths: + - path: /webstatus + pathType: Prefix + backend: + service: + name: webstatus + port: + number: 80 diff --git a/deploy/k8s/helm-simple/webstatus/templates/service.yaml b/deploy/k8s/helm-simple/webstatus/templates/service.yaml new file mode 100644 index 000000000..107b8600d --- /dev/null +++ b/deploy/k8s/helm-simple/webstatus/templates/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: webstatus + labels: + app: eshop + service: webstatus +spec: + ports: + - port: 80 + protocol: TCP + name: http + selector: + service: webstatus diff --git a/deploy/k8s/implementation-script.sh b/deploy/k8s/implementation-script.sh new file mode 100644 index 000000000..b41ff09d3 --- /dev/null +++ b/deploy/k8s/implementation-script.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +# Color theming +. <(cat ../../../../infrastructure/scripts/theme.sh) + +## Add the discount coupon field in the checkout view. +echo "Uncommenting HTML in src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html..." +sed -i -E "/DISCOUNT-COUPON-COMMENT/s//\1/" ../../src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html + +## Show the discount amount in the order details view. +echo "Uncommenting HTML in src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html..." +sed -i -E "/DISCOUNT-COUPON-COMMENT/s//\1/" ../../src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html + +echo "Creating a Helm chart (with templates) for the coupon service in deploy/k8s/helm-simple/coupon..." +## Add the Helm chart to deploy the coupon service to AKS. +mkdir helm-simple/coupon +mkdir helm-simple/coupon/templates + +# helm-simple/coupon/Chart.yaml +cat >helm-simple/coupon/Chart.yaml <helm-simple/coupon/templates/deployment.yaml <helm-simple/coupon/templates/service.yaml <helm-simple/coupon/templates/configmap.yaml <helm-simple/coupon/templates/ingress.yaml < _mapper; + + public CouponController(ICouponRepository couponRepository, IMapper mapper) + { + _couponRepository = couponRepository; + _mapper = mapper; + } + + // Add the GetCouponByCodeAsync method + [HttpGet("{code}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> GetCouponByCodeAsync(string code) + { + var coupon = await _couponRepository.FindCouponByCodeAsync(code); + + if (coupon is null || coupon.Consumed) + { + return NotFound(); + } + + var couponDto = _mapper.Translate(coupon); + + return couponDto; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Coupon.API.csproj b/src/Services/Coupon/Coupon.API/Coupon.API.csproj new file mode 100644 index 000000000..44116b094 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Coupon.API.csproj @@ -0,0 +1,40 @@ + + + + net6.0 + 1d5bc948-90f1-4906-a1f8-8edaa1ed9e2e + Linux + ..\..\..\.. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Coupon/Coupon.API/CouponSettings.cs b/src/Services/Coupon/Coupon.API/CouponSettings.cs new file mode 100644 index 000000000..f46ac768d --- /dev/null +++ b/src/Services/Coupon/Coupon.API/CouponSettings.cs @@ -0,0 +1,15 @@ +namespace Coupon.API +{ + public class CouponSettings + { + public string ConnectionString { get; set; } + + public string CouponMongoDatabase { get; set; } + + public string EventBusConnection { get; set; } + + public bool UseCustomizationData { get; set; } + + public bool AzureStorageEnabled { get; set; } + } +} diff --git a/src/Services/Coupon/Coupon.API/Dockerfile b/src/Services/Coupon/Coupon.API/Dockerfile new file mode 100644 index 000000000..959d35314 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Dockerfile @@ -0,0 +1,59 @@ +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src + +# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles +# to take advantage of Docker's build cache, to speed up local container builds +COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" + +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" +COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" +COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" +COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" +COPY "BuildingBlocks/EventBus/EventBus/EventBus.csproj" "BuildingBlocks/EventBus/EventBus/EventBus.csproj" +COPY "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" +COPY "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" +COPY "BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj" "BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj" +COPY "BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj" "BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj" +COPY "BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj" "BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj" +COPY "Services/Basket/Basket.API/Basket.API.csproj" "Services/Basket/Basket.API/Basket.API.csproj" +COPY "Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj" "Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj" +COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" +COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj" +COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" +COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" +COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj" +COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj" +COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" +COPY "Services/Ordering/Ordering.Domain/Ordering.Domain.csproj" "Services/Ordering/Ordering.Domain/Ordering.Domain.csproj" +COPY "Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj" "Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj" +COPY "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj" "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj" +COPY "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" +COPY "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" +COPY "Services/Payment/Payment.API/Payment.API.csproj" "Services/Payment/Payment.API/Payment.API.csproj" +COPY "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" +COPY "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" +COPY "Web/WebhookClient/WebhookClient.csproj" "Web/WebhookClient/WebhookClient.csproj" +COPY "Web/WebMVC/WebMVC.csproj" "Web/WebMVC/WebMVC.csproj" +COPY "Web/WebSPA/WebSPA.csproj" "Web/WebSPA/WebSPA.csproj" +COPY "Web/WebStatus/WebStatus.csproj" "Web/WebStatus/WebStatus.csproj" + +COPY "docker-compose.dcproj" "docker-compose.dcproj" + +COPY "NuGet.config" "NuGet.config" + +RUN dotnet restore "eShopOnContainers-ServicesAndWebApps.sln" + +COPY . . +WORKDIR /src/Services/Coupon/Coupon.API +RUN dotnet publish --no-restore -c Release -o /app + +FROM build AS publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "Coupon.API.dll"] \ No newline at end of file diff --git a/src/Services/Coupon/Coupon.API/Dtos/CouponDto.cs b/src/Services/Coupon/Coupon.API/Dtos/CouponDto.cs new file mode 100644 index 000000000..7893e8eaa --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Dtos/CouponDto.cs @@ -0,0 +1,9 @@ +namespace Coupon.API.Dtos +{ + public class CouponDto + { + public int Discount { get; set; } + + public string Code { get; set; } + } +} diff --git a/src/Services/Coupon/Coupon.API/Dtos/IMapper.cs b/src/Services/Coupon/Coupon.API/Dtos/IMapper.cs new file mode 100644 index 000000000..bad856fd5 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Dtos/IMapper.cs @@ -0,0 +1,7 @@ +namespace Coupon.API.Dtos +{ + public interface IMapper + { + TResult Translate(TEntity entity); + } +} diff --git a/src/Services/Coupon/Coupon.API/Dtos/Mapper.cs b/src/Services/Coupon/Coupon.API/Dtos/Mapper.cs new file mode 100644 index 000000000..4a471c1da --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Dtos/Mapper.cs @@ -0,0 +1,16 @@ +namespace Coupon.API.Dtos +{ + using Coupon.API.Infrastructure.Models; + + public class Mapper : IMapper + { + public CouponDto Translate(Coupon entity) + { + return new CouponDto + { + Code = entity.Code, + Discount = entity.Discount + }; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Extensions/IHostBuilderExtensions.cs b/src/Services/Coupon/Coupon.API/Extensions/IHostBuilderExtensions.cs new file mode 100644 index 000000000..a5c4e97e9 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Extensions/IHostBuilderExtensions.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Data.SqlClient; +using Coupon.API.IntegrationEvents.EventHandlers; +using Coupon.API.IntegrationEvents.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Polly; + +namespace Coupon.API.Extensions +{ + public static class IHostBuilderExtensions + { + public static IHost SeedDatabaseStrategy(this IHost host, Action seeder) + { + using (var scope = host.Services.CreateScope()) + { + var context = scope.ServiceProvider.GetService(); + + var policy = Policy.Handle() + .WaitAndRetry(new TimeSpan[] + { + TimeSpan.FromSeconds(3), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(8), + }); + + policy.Execute(() => + { + seeder.Invoke(context); + }); + } + + return host; + } + + public static IHost SubscribersIntegrationEvents(this IHost host) + { + using (var scope = host.Services.CreateScope()) + { + var eventBus = scope.ServiceProvider.GetRequiredService(); + + eventBus.Subscribe(); + } + + return host; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Extensions/IServiceCollectionExtensions.cs b/src/Services/Coupon/Coupon.API/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 000000000..45c57cc6b --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,227 @@ +namespace Coupon.API.Extensions +{ + using Autofac; + using Coupon.API.Dtos; + using Coupon.API.Filters; + using Coupon.API.Infrastructure.Models; + using Coupon.API.Infrastructure.Repositories; + using Microsoft.AspNetCore.Authentication.JwtBearer; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Mvc; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Diagnostics.HealthChecks; + using Microsoft.Extensions.Logging; + using Microsoft.OpenApi.Models; + using RabbitMQ.Client; + using System; + using System.Collections.Generic; + + public static class IServiceCollectionExtensions + { + public static IServiceCollection AddCouponRegister(this IServiceCollection services, IConfiguration configuration) + { + services.AddTransient() + .AddTransient(service => + { + var serviceBusConnectionString = configuration["EventBusConnection"]; + + return new DefaultServiceBusPersisterConnection(serviceBusConnectionString); + }) + .AddTransient(service => + { + var factory = new ConnectionFactory() + { + HostName = configuration["EventBusConnection"], + DispatchConsumersAsync = true + }; + + var retryCount = 5; + + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new DefaultRabbitMQPersistentConnection(factory, service.GetService>(), retryCount); + }) + .AddTransient() + .AddTransient() + .AddTransient, Mapper>(); + + return services; + } + + public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) + { + services.AddSwaggerGen(options => + { + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "eShopOnContainers - Coupon HTTP API", + Version = "v1", + Description = "The Coupon Service HTTP API" + }); + + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() + { + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "coupon", "Coupon API" } + } + } + } + }); + + options.OperationFilter(); + }); + + return services; + } + + public static IServiceCollection AddCustomSettings(this IServiceCollection services, IConfiguration configuration) + { + services.Configure(configuration); + services.Configure(options => + { + options.InvalidModelStateResponseFactory = context => + { + var problemDetails = new ValidationProblemDetails(context.ModelState) + { + Instance = context.HttpContext.Request.Path, + Status = StatusCodes.Status400BadRequest, + Detail = "Please refer to the errors property for additional details." + }; + + return new BadRequestObjectResult(problemDetails) + { + ContentTypes = { "application/problem+json", "application/problem+xml" } + }; + }; + }); + + return services; + } + + public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) + { + var subscriptionClientName = configuration["SubscriptionClientName"]; + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var serviceBusPersisterConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + return new EventBusServiceBus(serviceBusPersisterConnection, logger, + eventBusSubcriptionsManager, iLifetimeScope, subscriptionClientName); + }); + } + else + { + services.AddSingleton(sp => + { + var rabbitMQPersistentConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + var retryCount = 5; + + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + }); + } + + return services; + } + + public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) + { + var accountName = configuration.GetValue("AzureStorageAccountName"); + var accountKey = configuration.GetValue("AzureStorageAccountKey"); + + var hcBuilder = services.AddHealthChecks(); + + hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()) + .AddMongoDb( + configuration["ConnectionString"], + name: "CouponCollection-check", + tags: new string[] { "couponcollection" }); + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + hcBuilder.AddAzureServiceBusTopic( + configuration["EventBusConnection"], + topicName: "eshop_event_bus", + name: "coupon-servicebus-check", + tags: new string[] { "servicebus" }); + } + else + { + hcBuilder.AddRabbitMQ( + $"amqp://{configuration["EventBusConnection"]}", + name: "coupon-rabbitmqbus-check", + tags: new string[] { "rabbitmqbus" }); + } + + return services; + } + + public static IServiceCollection AddCustomPolicies(this IServiceCollection services) + { + services.AddCors(options => + { + options.AddPolicy("CorsPolicy", + builder => builder.SetIsOriginAllowed((host) => true) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials()); + }); + + return services; + } + + public static IServiceCollection AddAppInsights(this IServiceCollection services, IConfiguration configuration) + { + services.AddApplicationInsightsTelemetry(configuration); + services.AddApplicationInsightsKubernetesEnricher(); + + return services; + } + + public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) + { + return services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(options => + { + options.Authority = configuration["IdentityUrl"]; + options.RequireHttpsMetadata = false; + options.Audience = "coupon"; + }).Services; + } + + public static IServiceCollection AddCustomAuthorization(this IServiceCollection services) => services.AddAuthorization(); + } +} diff --git a/src/Services/Coupon/Coupon.API/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Coupon/Coupon.API/Filters/AuthorizeCheckOperationFilter.cs new file mode 100644 index 000000000..726b537d4 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Filters/AuthorizeCheckOperationFilter.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Coupon.API.Filters +{ + public class AuthorizeCheckOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || + context.MethodInfo.GetCustomAttributes(true).OfType().Any(); + + if (!hasAuthorize) return; + + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); + + var oAuthScheme = new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } + }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [oAuthScheme] = new [] { "CouponApi" } + } + }; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Filters/ValidateModelAttribute.cs b/src/Services/Coupon/Coupon.API/Filters/ValidateModelAttribute.cs new file mode 100644 index 000000000..59cc10917 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Filters/ValidateModelAttribute.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Coupon.API.Filters +{ + public class ValidateModelAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) + { + if (!context.ModelState.IsValid) + { + context.Result = new BadRequestObjectResult(context.ModelState); + } + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs b/src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs new file mode 100644 index 000000000..39c531381 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs @@ -0,0 +1,52 @@ +namespace Coupon.API.Infrastructure +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Coupon.API.Infrastructure.Models; + using Coupon.API.Infrastructure.Repositories; + + public class CouponSeed + { + public async Task SeedAsync(CouponContext context) + { + if (context.Coupons.EstimatedDocumentCount() == 0) + { + var coupons = new List + { + new Coupon + { + Code = "DISC-5", + Discount = 5 + }, + new Coupon + { + Code = "DISC-10", + Discount = 10 + }, + new Coupon + { + Code = "DISC-15", + Discount = 15 + }, + new Coupon + { + Code = "DISC-20", + Discount = 20 + }, + new Coupon + { + Code = "DISC-25", + Discount = 25 + }, + new Coupon + { + Code = "DISC-30", + Discount = 30 + } + }; + + await context.Coupons.InsertManyAsync(coupons); + } + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Infrastructure/Models/Coupon.cs b/src/Services/Coupon/Coupon.API/Infrastructure/Models/Coupon.cs new file mode 100644 index 000000000..13d628dbc --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Infrastructure/Models/Coupon.cs @@ -0,0 +1,20 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Coupon.API.Infrastructure.Models +{ + public class Coupon + { + [BsonIgnoreIfDefault] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + + public int Discount { get; set; } + + public string Code { get; set; } + + public bool Consumed { get; set; } + + public int OrderId { get; set; } + } +} diff --git a/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponContext.cs b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponContext.cs new file mode 100644 index 000000000..945dfe4f0 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponContext.cs @@ -0,0 +1,25 @@ +namespace Coupon.API.Infrastructure.Repositories +{ + using Coupon.API.Infrastructure.Models; + using Microsoft.Extensions.Options; + using MongoDB.Driver; + + public class CouponContext + { + private readonly IMongoDatabase _database = null; + + public CouponContext(IOptions settings) + { + var client = new MongoClient(settings.Value.ConnectionString); + + if (client is null) + { + throw new MongoConfigurationException("Cannot connect to the database. The connection string is not valid or the database is not accessible"); + } + + _database = client.GetDatabase(settings.Value.CouponMongoDatabase); + } + + public IMongoCollection Coupons => _database.GetCollection("CouponCollection"); + } +} diff --git a/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponRepository.cs b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponRepository.cs new file mode 100644 index 000000000..62bd8a3fa --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/CouponRepository.cs @@ -0,0 +1,42 @@ +namespace Coupon.API.Infrastructure.Repositories +{ + using System.Threading.Tasks; + using Coupon.API.Infrastructure.Models; + using MongoDB.Driver; + + public class CouponRepository : ICouponRepository + { + private readonly CouponContext _couponContext; + + public CouponRepository(CouponContext couponContext) + { + _couponContext = couponContext; + } + + public async Task UpdateCouponConsumedByCodeAsync(string code, int orderId) + { + var filter = Builders.Filter.Eq("Code", code); + var update = Builders.Update + .Set(coupon => coupon.Consumed, true) + .Set(coupon => coupon.OrderId, orderId); + + await _couponContext.Coupons.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = false }); + } + + public async Task UpdateCouponReleasedByOrderIdAsync(int orderId) + { + var filter = Builders.Filter.Eq("OrderId", orderId); + var update = Builders.Update + .Set(coupon => coupon.Consumed, false) + .Set(coupon => coupon.OrderId, 0); + + await _couponContext.Coupons.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = false }); + } + + public async Task FindCouponByCodeAsync(string code) + { + var filter = Builders.Filter.Eq("Code", code); + return await _couponContext.Coupons.Find(filter).FirstOrDefaultAsync(); + } + } +} diff --git a/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/ICouponRepository.cs b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/ICouponRepository.cs new file mode 100644 index 000000000..0dbac0693 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Infrastructure/Repositories/ICouponRepository.cs @@ -0,0 +1,14 @@ +namespace Coupon.API.Infrastructure.Repositories +{ + using System.Threading.Tasks; + using Coupon.API.Infrastructure.Models; + + public interface ICouponRepository + { + Task FindCouponByCodeAsync(string code); + + Task UpdateCouponConsumedByCodeAsync(string code, int orderId); + + Task UpdateCouponReleasedByOrderIdAsync(int orderId); + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler.cs new file mode 100644 index 000000000..d7f76acab --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; +using Coupon.API.Infrastructure.Repositories; +using Coupon.API.IntegrationEvents.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Serilog; +using Serilog.Context; + +namespace Coupon.API.IntegrationEvents.EventHandlers +{ + public class OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler : IIntegrationEventHandler + { + private readonly ICouponRepository _couponRepository; + private readonly IEventBus _eventBus; + + public OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler(ICouponRepository couponRepository, IEventBus eventBus) + { + _couponRepository = couponRepository; + _eventBus = eventBus; + } + + public async Task Handle(OrderStatusChangedToAwaitingCouponValidationIntegrationEvent @event) + { + await Task.Delay(3000); + + using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-Coupon.API")) + { + Log.Information("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, "Coupon.API", @event); + + var couponIntegrationEvent = await ProcessIntegrationEventAsync(@event); + + Log.Information("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", couponIntegrationEvent.Id, "Coupon.API", couponIntegrationEvent); + + _eventBus.Publish(couponIntegrationEvent); + } + } + + private async Task ProcessIntegrationEventAsync(OrderStatusChangedToAwaitingCouponValidationIntegrationEvent integrationEvent) + { + var coupon = await _couponRepository.FindCouponByCodeAsync(integrationEvent.Code); + + Log.Information("----- Coupon \"{CouponCode}\": {@Coupon}", integrationEvent.Code, coupon); + + if (coupon == null || coupon.Consumed) + { + return new OrderCouponRejectedIntegrationEvent(integrationEvent.OrderId, coupon.Code); + } + + Log.Information("Consumed coupon: {DiscountCode}", integrationEvent.Code); + + await _couponRepository.UpdateCouponConsumedByCodeAsync(integrationEvent.Code, integrationEvent.OrderId); + + return new OrderCouponConfirmedIntegrationEvent(integrationEvent.OrderId, coupon.Discount); + } + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToCancelledIntegrationEventHandler.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToCancelledIntegrationEventHandler.cs new file mode 100644 index 000000000..c6b931e40 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/EventHandlers/OrderStatusChangedToCancelledIntegrationEventHandler.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Coupon.API.Infrastructure.Repositories; +using Coupon.API.IntegrationEvents.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + +namespace Coupon.API.IntegrationEvents.EventHandlers +{ + public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler + { + private readonly ICouponRepository _couponRepository; + + public OrderStatusChangedToCancelledIntegrationEventHandler(ICouponRepository couponRepository) + { + _couponRepository = couponRepository; + } + + public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event) + { + await _couponRepository.UpdateCouponReleasedByOrderIdAsync(@event.OrderId); + } + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponConfirmedIntegrationEvent.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponConfirmedIntegrationEvent.cs new file mode 100644 index 000000000..59c33881f --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponConfirmedIntegrationEvent.cs @@ -0,0 +1,17 @@ +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + +namespace Coupon.API.IntegrationEvents.Events +{ + public record OrderCouponConfirmedIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public int Discount { get; } + + public OrderCouponConfirmedIntegrationEvent(int orderId, int discount) + { + OrderId = orderId; + Discount = discount; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponRejectedIntegrationEvent.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponRejectedIntegrationEvent.cs new file mode 100644 index 000000000..cc0596b8b --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderCouponRejectedIntegrationEvent.cs @@ -0,0 +1,17 @@ +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + +namespace Coupon.API.IntegrationEvents.Events +{ + public record OrderCouponRejectedIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public string Code { get; } + + public OrderCouponRejectedIntegrationEvent(int orderId, string code) + { + OrderId = orderId; + Code = code; + } + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToAwaitingCouponValidationIntegrationEvent.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToAwaitingCouponValidationIntegrationEvent.cs new file mode 100644 index 000000000..be870ff70 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToAwaitingCouponValidationIntegrationEvent.cs @@ -0,0 +1,20 @@ +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Newtonsoft.Json; + +namespace Coupon.API.IntegrationEvents.Events +{ + public record OrderStatusChangedToAwaitingCouponValidationIntegrationEvent : IntegrationEvent + { + [JsonProperty] + public int OrderId { get; private set; } + + [JsonProperty] + public string OrderStatus { get; private set; } + + [JsonProperty] + public string BuyerName { get; private set; } + + [JsonProperty] + public string Code { get; private set; } + } +} diff --git a/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs new file mode 100644 index 000000000..6ca1d51c1 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs @@ -0,0 +1,20 @@ +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Newtonsoft.Json; + +namespace Coupon.API.IntegrationEvents.Events +{ + public record OrderStatusChangedToCancelledIntegrationEvent : IntegrationEvent + { + [JsonProperty] + public int OrderId { get; private set; } + + [JsonProperty] + public string OrderStatus { get; private set; } + + [JsonProperty] + public string BuyerName { get; private set; } + + [JsonProperty] + public string DiscountCode { get; private set; } + } +} diff --git a/src/Services/Coupon/Coupon.API/Program.cs b/src/Services/Coupon/Coupon.API/Program.cs new file mode 100644 index 000000000..e00001af0 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Program.cs @@ -0,0 +1,53 @@ +using System.IO; +using Autofac.Extensions.DependencyInjection; +using Coupon.API.Extensions; +using Coupon.API.Infrastructure; +using Coupon.API.Infrastructure.Repositories; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Events; + +namespace Coupon.API +{ + public class Program + { + public static void Main(string[] args) => + CreateHostBuilder(args) + .Build() + .SeedDatabaseStrategy(context => new CouponSeed().SeedAsync(context).Wait()) + .SubscribersIntegrationEvents() + .Run(); + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureAppConfiguration((host, builder) => + { + builder.SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{host.HostingEnvironment.EnvironmentName}.json", optional: false, reloadOnChange: true) + .AddEnvironmentVariables(); + + var config = builder.Build(); + + if (config.GetValue("UseVault", false)) + { + builder.AddAzureKeyVault($"https://{config["Vault:Name"]}.vault.azure.net/", config["Vault:ClientId"], config["Vault:ClientSecret"]); + } + }) + .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()) + .UseSerilog((host, builder) => + { + builder.MinimumLevel.Verbose() + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .Enrich.WithProperty("ApplicationContext", host.HostingEnvironment.ApplicationName) + .Enrich.FromLogContext() + .WriteTo.Console() + .WriteTo.Seq(string.IsNullOrWhiteSpace(host.Configuration["Serilog:SeqServerUrl"]) ? "http://seq" : host.Configuration["Serilog:SeqServerUrl"]) + .WriteTo.Http(string.IsNullOrWhiteSpace(host.Configuration["Serilog:LogstashUrl"]) ? "http://logstash:8080" : host.Configuration["Serilog:LogstashUrl"]) + .ReadFrom.Configuration(host.Configuration); + }); + } +} diff --git a/src/Services/Coupon/Coupon.API/Properties/launchSettings.json b/src/Services/Coupon/Coupon.API/Properties/launchSettings.json new file mode 100644 index 000000000..fdb25b10d --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Coupon.API": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:59058;http://localhost:59059" + } + } +} \ No newline at end of file diff --git a/src/Services/Coupon/Coupon.API/Startup.cs b/src/Services/Coupon/Coupon.API/Startup.cs new file mode 100644 index 000000000..586dc7506 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/Startup.cs @@ -0,0 +1,95 @@ +using Coupon.API.Extensions; +using Coupon.API.Filters; +using Coupon.API.IntegrationEvents.EventHandlers; +using Coupon.API.IntegrationEvents.Events; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; + +namespace Coupon.API +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(options => options.Filters.Add()); + + services.AddCustomSettings(Configuration) + .AddCouponRegister(Configuration) + .AddCustomPolicies() + .AddAppInsights(Configuration) + .AddEventBus(Configuration) + .AddCustomAuthentication(Configuration) + .AddCustomAuthorization() + .AddSwagger(Configuration) + .AddCustomHealthCheck(Configuration); + + services.AddTransient, OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler>(); + services.AddTransient, OrderStatusChangedToCancelledIntegrationEventHandler>(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + var pathBase = Configuration["PATH_BASE"]; + + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } + + app.UseSwagger() + .UseSwaggerUI(options => + { + options.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Coupon.API V1"); + options.OAuthClientId("couponswaggerui"); + options.OAuthAppName("eShop-Learn.Coupon.API Swagger UI"); + }) + .UseCors("CorsPolicy") + .UseRouting() + .UseAuthentication() + .UseAuthorization() + .UseEndpoints(endpoints => + { + endpoints.MapControllers(); + // Add the endpoints.MapHealthChecks code + endpoints.MapHealthChecks("/hc", new HealthCheckOptions + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); + + ConfigureEventBus(app); + } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + + eventBus.Subscribe>(); + eventBus.Subscribe>(); + } + } +} diff --git a/src/Services/Coupon/Coupon.API/appsettings.Development.json b/src/Services/Coupon/Coupon.API/appsettings.Development.json new file mode 100644 index 000000000..a00a59a10 --- /dev/null +++ b/src/Services/Coupon/Coupon.API/appsettings.Development.json @@ -0,0 +1,18 @@ +{ + "ConnectionString": "mongodb://localhost:27017", + "CouponMongoDatabase": "CouponDb", + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Warning", + "Microsoft.eShopOnContainers": "Debug", + "System": "Warning" + } + } + }, + "IdentityUrlExternal": "http://localhost:5105", + "IdentityUrl": "http://localhost:5105", + "AzureServiceBusEnabled": false, + "EventBusConnection": "localhost" +} diff --git a/src/Services/Coupon/Coupon.API/appsettings.json b/src/Services/Coupon/Coupon.API/appsettings.json new file mode 100644 index 000000000..d93e3cd7f --- /dev/null +++ b/src/Services/Coupon/Coupon.API/appsettings.json @@ -0,0 +1,28 @@ +{ + "ConnectionString": null, + "CouponMongoDatabase": "CouponDb", + "UseCustomizationData": false, + "Serilog": { + "SeqServerUrl": null, + "LogstashUrl": null, + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.eShopOnContainers": "Information", + "System": "Warning" + } + } + }, + "SubscriptionClientName": "Coupon", + "ApplicationInsights": { + "InstrumentationKey": "" + }, + "EventBusRetryCount": 5, + "UseVault": false, + "Vault": { + "Name": "eshop", + "ClientId": "your-client-id", + "ClientSecret": "your-client-secret" + } +} diff --git a/src/Services/Identity/Identity.API/Dockerfile b/src/Services/Identity/Identity.API/Dockerfile index 674cc4ec1..7d706eecb 100644 --- a/src/Services/Identity/Identity.API/Dockerfile +++ b/src/Services/Identity/Identity.API/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Services/Ordering/Ordering.API/Dockerfile b/src/Services/Ordering/Ordering.API/Dockerfile index 905d3bcd0..de368a1d0 100644 --- a/src/Services/Ordering/Ordering.API/Dockerfile +++ b/src/Services/Ordering/Ordering.API/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile index 0a5ce8f0c..4eeb52c5b 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile index 33771bf1f..6e9769000 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile +++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Services/Payment/Payment.API/Dockerfile b/src/Services/Payment/Payment.API/Dockerfile index e91ed767b..82c1f2814 100644 --- a/src/Services/Payment/Payment.API/Dockerfile +++ b/src/Services/Payment/Payment.API/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Services/Webhooks/Webhooks.API/Dockerfile b/src/Services/Webhooks/Webhooks.API/Dockerfile index b5fb88684..f9f22033f 100644 --- a/src/Services/Webhooks/Webhooks.API/Dockerfile +++ b/src/Services/Webhooks/Webhooks.API/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Web/WebMVC/Dockerfile b/src/Web/WebMVC/Dockerfile index 470de25d2..9000abd82 100644 --- a/src/Web/WebMVC/Dockerfile +++ b/src/Web/WebMVC/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html b/src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html index e0ea4f722..81f616514 100644 --- a/src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html +++ b/src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html @@ -39,6 +39,15 @@
${{order.total | number:'.2-2'}}
+
+
Subtotal
+
${{order.subtotal | number:'.2-2'}}
+
+
+
{{order.coupon}}
+
- ${{order.discount | number:'.2-2'}}
+
+ diff --git a/src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html b/src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html index 18311597a..9ab4be684 100644 --- a/src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html +++ b/src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html @@ -89,6 +89,38 @@
${{ order.total | number:'.2-2'}}
+
+
Subtotal
+
${{order.total | number:'.2-2'}}
+
+ +
+
+
+
Have a discount code?
+
+ + +
+
{{couponValidationMessage}}
+
+
+
+
{{coupon?.code}}
+
+
-${{coupon?.discount | number:'.2-2'}}
+
+
+
+
Back to basket diff --git a/src/Web/WebSPA/Dockerfile b/src/Web/WebSPA/Dockerfile index 00ff8b3b5..f2cbce1b8 100644 --- a/src/Web/WebSPA/Dockerfile +++ b/src/Web/WebSPA/Dockerfile @@ -20,6 +20,7 @@ WORKDIR /src # Create this "restore-solution" section by running ./Create-DockerfileSolutionRestore.ps1, to optimize build cache reuse COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Web/WebStatus/Dockerfile b/src/Web/WebStatus/Dockerfile index 47ecbd9e4..fc0767dc1 100644 --- a/src/Web/WebStatus/Dockerfile +++ b/src/Web/WebStatus/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/Web/WebhookClient/Dockerfile b/src/Web/WebhookClient/Dockerfile index c25957029..aa8052a36 100644 --- a/src/Web/WebhookClient/Dockerfile +++ b/src/Web/WebhookClient/Dockerfile @@ -10,6 +10,7 @@ WORKDIR /src # to take advantage of Docker's build cache, to speed up local container builds COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln" +COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj" COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" diff --git a/src/docker-compose.override.yml b/src/docker-compose.override.yml index 8251636e9..bf9e9b9e5 100644 --- a/src/docker-compose.override.yml +++ b/src/docker-compose.override.yml @@ -58,6 +58,31 @@ services: ports: - "5105:80" + coupon-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_COUPON_DB:-mongodb://nosqldata} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - CheckUpdateTime=30000 + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ=Verbose + - Serilog__MinimumLevel__Override__ordering-api=Verbose + - PATH_BASE=/coupon-api + - GRPC_PORT=81 + - PORT=80 + ports: + - "5106:80" + - "9106:81" + basket-api: environment: - ASPNETCORE_ENVIRONMENT=Development diff --git a/src/docker-compose.yml b/src/docker-compose.yml index 3ae5d431a..06f77525c 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -35,6 +35,20 @@ services: - identity-api - rabbitmq + coupon-api: + image: ${REGISTRY:-eshop}/coupon.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Coupon/Coupon.API/Dockerfile + depends_on: + - nosqldata + - sqldata + - identity-api + - rabbitmq + - ordering-api + - catalog-api + - basket-api + catalog-api: image: ${REGISTRY:-eshop}/catalog.api:${PLATFORM:-linux}-${TAG:-latest} build: diff --git a/src/eShopOnContainers-ServicesAndWebApps.sln b/src/eShopOnContainers-ServicesAndWebApps.sln index 446614fc0..57f2b454d 100644 --- a/src/eShopOnContainers-ServicesAndWebApps.sln +++ b/src/eShopOnContainers-ServicesAndWebApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29020.237 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" EndProject @@ -124,6 +124,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{373D8AA1 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Tests", "BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{95D735BE-2899-4495-BE3F-2600E93B4E3C}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Coupon", "Coupon", "{8FC824CA-8CBB-4897-B4A3-3400DC682680}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Coupon.API", "Services\Coupon\Coupon.API\Coupon.API.csproj", "{F56AB28C-4A57-461E-B69F-EA4DA9D987D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -450,8 +454,8 @@ Global {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x64.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.ActiveCfg = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.Build.0 = Release|Any CPU - {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.ActiveCfg = Debug|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.Build.0 = Debug|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|iPhone.ActiveCfg = Debug|Any CPU @@ -1530,6 +1534,54 @@ Global {95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x64.Build.0 = Release|Any CPU {95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.ActiveCfg = Release|Any CPU {95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|ARM.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|iPhone.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|x64.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|x64.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|x86.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.AppStore|x86.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|ARM.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|iPhone.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|x64.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Debug|x86.Build.0 = Debug|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|Any CPU.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|ARM.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|ARM.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|iPhone.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|iPhone.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|x64.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|x64.Build.0 = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|x86.ActiveCfg = Release|Any CPU + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1588,6 +1640,8 @@ Global {B62E859F-825E-4C8B-93EC-5966EACFD026} = {798BFC44-2CCD-45FA-B37A-5173B03C2B30} {373D8AA1-36BE-49EC-89F0-6CB736666285} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} {95D735BE-2899-4495-BE3F-2600E93B4E3C} = {373D8AA1-36BE-49EC-89F0-6CB736666285} + {8FC824CA-8CBB-4897-B4A3-3400DC682680} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} + {F56AB28C-4A57-461E-B69F-EA4DA9D987D3} = {8FC824CA-8CBB-4897-B4A3-3400DC682680} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}