@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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/<!--DISCOUNT-COUPON-COMMENT\*\*(.*)-->/\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/<!--DISCOUNT-COUPON-COMMENT\*\*(.*)-->/\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 <<EOL | |||
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 | |||
EOL | |||
# helm-simple/coupon/templates/deployment.yaml | |||
cat >helm-simple/coupon/templates/deployment.yaml <<EOL | |||
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 | |||
EOL | |||
# helm-simple/coupon/templates/service.yaml | |||
cat >helm-simple/coupon/templates/service.yaml <<EOL | |||
kind: Service | |||
apiVersion: v1 | |||
metadata: | |||
name: coupon-api | |||
labels: | |||
app: eshop | |||
service: coupon | |||
spec: | |||
ports: | |||
- port: 80 | |||
protocol: TCP | |||
name: http | |||
selector: | |||
service: coupon | |||
EOL | |||
# helm-simple/coupon/templates/configmap.yaml | |||
cat >helm-simple/coupon/templates/configmap.yaml <<EOL | |||
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 | |||
EOL | |||
# helm-simple/coupon/templates/ingress.yaml | |||
cat >helm-simple/coupon/templates/ingress.yaml <<EOL | |||
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 | |||
EOL | |||
## Add the coupon service endpoints in the aggregator | |||
echo "Adding coupon service endpoints to the API gateway in deploy/k8s/helm-simple/webshoppingagg/templates/configmap.yaml..." | |||
sed -i -E "/DISCOUNT-COUPON-COMMENT/s/#DISCOUNT-COUPON-COMMENT\*\*//" helm-simple/webshoppingagg/templates/configmap.yaml | |||
## Add the coupon service as a health check item in the webstatus application | |||
echo "Adding coupon service as a WebStatus health check item in deploy/k8s/helm-simple/webstatus/templates/configmap.yaml..." | |||
sed -i -E "/DISCOUNT-COUPON-COMMENT/s/#DISCOUNT-COUPON-COMMENT\*\*//" helm-simple/webstatus/templates/configmap.yaml | |||
echo " " | |||
echo "Implementation script done!" |
@ -0,0 +1,45 @@ | |||
namespace Coupon.API.Controllers | |||
{ | |||
using System.Net; | |||
using System.Threading.Tasks; | |||
using Coupon.API.Dtos; | |||
using Coupon.API.Infrastructure.Models; | |||
using Coupon.API.Infrastructure.Repositories; | |||
using Microsoft.AspNetCore.Authorization; | |||
using Microsoft.AspNetCore.Http; | |||
using Microsoft.AspNetCore.Mvc; | |||
[Authorize] | |||
[ApiController] | |||
[Route("api/v1/[controller]")] | |||
public class CouponController : ControllerBase | |||
{ | |||
private readonly ICouponRepository _couponRepository; | |||
private readonly IMapper<CouponDto, Coupon> _mapper; | |||
public CouponController(ICouponRepository couponRepository, IMapper<CouponDto, Coupon> mapper) | |||
{ | |||
_couponRepository = couponRepository; | |||
_mapper = mapper; | |||
} | |||
// Add the GetCouponByCodeAsync method | |||
[HttpGet("{code}")] | |||
[ProducesResponseType(StatusCodes.Status200OK)] | |||
[ProducesResponseType(StatusCodes.Status400BadRequest)] | |||
[ProducesResponseType(StatusCodes.Status404NotFound)] | |||
public async Task<ActionResult<CouponDto>> GetCouponByCodeAsync(string code) | |||
{ | |||
var coupon = await _couponRepository.FindCouponByCodeAsync(code); | |||
if (coupon is null || coupon.Consumed) | |||
{ | |||
return NotFound(); | |||
} | |||
var couponDto = _mapper.Translate(coupon); | |||
return couponDto; | |||
} | |||
} | |||
} |
@ -0,0 +1,40 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<PropertyGroup> | |||
<TargetFramework>net6.0</TargetFramework> | |||
<UserSecretsId>1d5bc948-90f1-4906-a1f8-8edaa1ed9e2e</UserSecretsId> | |||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> | |||
<DockerfileContext>..\..\..\..</DockerfileContext> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.3" /> | |||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1" /> | |||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" /> | |||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" /> | |||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.4" /> | |||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" /> | |||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.20.0" /> | |||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2" /> | |||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" /> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.23" /> | |||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.0" /> | |||
<PackageReference Include="MongoDB.Driver.Core" Version="2.13.3" /> | |||
<PackageReference Include="Polly" Version="7.2.3" /> | |||
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" /> | |||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" /> | |||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" /> | |||
<PackageReference Include="Serilog.Sinks.Http" Version="7.2.0" /> | |||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.1" /> | |||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" /> | |||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.16.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" /> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" /> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@ -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; } | |||
} | |||
} |
@ -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"] |
@ -0,0 +1,9 @@ | |||
namespace Coupon.API.Dtos | |||
{ | |||
public class CouponDto | |||
{ | |||
public int Discount { get; set; } | |||
public string Code { get; set; } | |||
} | |||
} |
@ -0,0 +1,7 @@ | |||
namespace Coupon.API.Dtos | |||
{ | |||
public interface IMapper<TResult, TEntity> | |||
{ | |||
TResult Translate(TEntity entity); | |||
} | |||
} |
@ -0,0 +1,16 @@ | |||
namespace Coupon.API.Dtos | |||
{ | |||
using Coupon.API.Infrastructure.Models; | |||
public class Mapper : IMapper<CouponDto, Coupon> | |||
{ | |||
public CouponDto Translate(Coupon entity) | |||
{ | |||
return new CouponDto | |||
{ | |||
Code = entity.Code, | |||
Discount = entity.Discount | |||
}; | |||
} | |||
} | |||
} |
@ -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<TContext>(this IHost host, Action<TContext> seeder) | |||
{ | |||
using (var scope = host.Services.CreateScope()) | |||
{ | |||
var context = scope.ServiceProvider.GetService<TContext>(); | |||
var policy = Policy.Handle<SqlException>() | |||
.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<IEventBus>(); | |||
eventBus.Subscribe<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent, OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler>(); | |||
} | |||
return host; | |||
} | |||
} | |||
} |
@ -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<ICouponRepository, CouponRepository>() | |||
.AddTransient<IServiceBusPersisterConnection, DefaultServiceBusPersisterConnection>(service => | |||
{ | |||
var serviceBusConnectionString = configuration["EventBusConnection"]; | |||
return new DefaultServiceBusPersisterConnection(serviceBusConnectionString); | |||
}) | |||
.AddTransient<IRabbitMQPersistentConnection, DefaultRabbitMQPersistentConnection>(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<ILogger<DefaultRabbitMQPersistentConnection>>(), retryCount); | |||
}) | |||
.AddTransient<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>() | |||
.AddTransient<CouponContext>() | |||
.AddTransient<IMapper<CouponDto, Coupon>, 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<string>("IdentityUrlExternal")}/connect/authorize"), | |||
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"), | |||
Scopes = new Dictionary<string, string>() | |||
{ | |||
{ "coupon", "Coupon API" } | |||
} | |||
} | |||
} | |||
}); | |||
options.OperationFilter<AuthorizeCheckOperationFilter>(); | |||
}); | |||
return services; | |||
} | |||
public static IServiceCollection AddCustomSettings(this IServiceCollection services, IConfiguration configuration) | |||
{ | |||
services.Configure<CouponSettings>(configuration); | |||
services.Configure<ApiBehaviorOptions>(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<bool>("AzureServiceBusEnabled")) | |||
{ | |||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | |||
{ | |||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | |||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | |||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | |||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||
return new EventBusServiceBus(serviceBusPersisterConnection, logger, | |||
eventBusSubcriptionsManager, iLifetimeScope, subscriptionClientName); | |||
}); | |||
} | |||
else | |||
{ | |||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp => | |||
{ | |||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>(); | |||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | |||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>(); | |||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||
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<string>("AzureStorageAccountName"); | |||
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey"); | |||
var hcBuilder = services.AddHealthChecks(); | |||
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()) | |||
.AddMongoDb( | |||
configuration["ConnectionString"], | |||
name: "CouponCollection-check", | |||
tags: new string[] { "couponcollection" }); | |||
if (configuration.GetValue<bool>("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(); | |||
} | |||
} |
@ -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<AuthorizeAttribute>().Any() || | |||
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().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<OpenApiSecurityRequirement> | |||
{ | |||
new OpenApiSecurityRequirement | |||
{ | |||
[oAuthScheme] = new [] { "CouponApi" } | |||
} | |||
}; | |||
} | |||
} | |||
} |
@ -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); | |||
} | |||
} | |||
} | |||
} |
@ -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<Coupon> | |||
{ | |||
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); | |||
} | |||
} | |||
} | |||
} |
@ -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; } | |||
} | |||
} |
@ -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<CouponSettings> 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<Coupon> Coupons => _database.GetCollection<Coupon>("CouponCollection"); | |||
} | |||
} |
@ -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<Coupon>.Filter.Eq("Code", code); | |||
var update = Builders<Coupon>.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<Coupon>.Filter.Eq("OrderId", orderId); | |||
var update = Builders<Coupon>.Update | |||
.Set(coupon => coupon.Consumed, false) | |||
.Set(coupon => coupon.OrderId, 0); | |||
await _couponContext.Coupons.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = false }); | |||
} | |||
public async Task<Coupon> FindCouponByCodeAsync(string code) | |||
{ | |||
var filter = Builders<Coupon>.Filter.Eq("Code", code); | |||
return await _couponContext.Coupons.Find(filter).FirstOrDefaultAsync(); | |||
} | |||
} | |||
} |
@ -0,0 +1,14 @@ | |||
namespace Coupon.API.Infrastructure.Repositories | |||
{ | |||
using System.Threading.Tasks; | |||
using Coupon.API.Infrastructure.Models; | |||
public interface ICouponRepository | |||
{ | |||
Task<Coupon> FindCouponByCodeAsync(string code); | |||
Task UpdateCouponConsumedByCodeAsync(string code, int orderId); | |||
Task UpdateCouponReleasedByOrderIdAsync(int orderId); | |||
} | |||
} |
@ -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<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent> | |||
{ | |||
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<IntegrationEvent> 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); | |||
} | |||
} | |||
} |
@ -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<OrderStatusChangedToCancelledIntegrationEvent> | |||
{ | |||
private readonly ICouponRepository _couponRepository; | |||
public OrderStatusChangedToCancelledIntegrationEventHandler(ICouponRepository couponRepository) | |||
{ | |||
_couponRepository = couponRepository; | |||
} | |||
public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event) | |||
{ | |||
await _couponRepository.UpdateCouponReleasedByOrderIdAsync(@event.OrderId); | |||
} | |||
} | |||
} |
@ -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; | |||
} | |||
} | |||
} |
@ -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; | |||
} | |||
} | |||
} |
@ -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; } | |||
} | |||
} |
@ -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; } | |||
} | |||
} |
@ -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<CouponContext>(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<Startup>()) | |||
.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); | |||
}); | |||
} | |||
} |
@ -0,0 +1,12 @@ | |||
{ | |||
"profiles": { | |||
"Coupon.API": { | |||
"commandName": "Project", | |||
"launchBrowser": true, | |||
"environmentVariables": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
}, | |||
"applicationUrl": "https://localhost:59058;http://localhost:59059" | |||
} | |||
} | |||
} |
@ -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<ValidateModelAttribute>()); | |||
services.AddCustomSettings(Configuration) | |||
.AddCouponRegister(Configuration) | |||
.AddCustomPolicies() | |||
.AddAppInsights(Configuration) | |||
.AddEventBus(Configuration) | |||
.AddCustomAuthentication(Configuration) | |||
.AddCustomAuthorization() | |||
.AddSwagger(Configuration) | |||
.AddCustomHealthCheck(Configuration); | |||
services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent>, OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler>(); | |||
services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>, 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<IEventBus>(); | |||
eventBus.Subscribe<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent>>(); | |||
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>>(); | |||
} | |||
} | |||
} |
@ -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" | |||
} |
@ -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" | |||
} | |||
} |