diff --git a/.dockerignore b/.dockerignore index e58ae957a..dd3d41423 100644 --- a/.dockerignore +++ b/.dockerignore @@ -28,9 +28,7 @@ cli-linux **/obj/ **/node_modules/ **/bower_components/ -**/wwwroot/lib/ -!**/wwwroot/lib/signalr/* -!**/wwwroot/lib/toastr/* +**/wwwroot/lib/* global.json **/appsettings.localhost.json src/Web/WebSPA/wwwroot/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c690a758..69800e3b7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,10 @@ bld/ # Visual Studio 2015 cache/options directory .vs/ + +# .js files created on build: +src/Web/WebMVC/wwwroot/js/site* + # Uncomment if you have tasks that create the project's static files in wwwroot **/wwwroot/lib/ !/wwwroot/lib/signalr @@ -263,3 +267,6 @@ pub/ /src/Web/WebMVC/wwwroot/css/site.min.css **/.kube/** .mfractor + +# Ignore HealthCheckdb +*healthchecksdb* \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..e0ff17a32 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# How to contribute to eShopOnContainers + +This repo is a reference and learning resource and everyone is invited to contribute, however not all PRs will be accepted into the main branch (**`dev`**). + +There's a general development strategy that's driven by @CESARDELATORRE, who chooses, or defines criteria for choosing, the issues to include in the codebase, given a bunch of constraints and other guidelines. + +However you can always get in touch with him, if you want to implement some general-interest feature in your repo and have it referenced from the [documentation](https://docs.microsoft.com/dotnet/standard/microservices-architecture/) or the [Microservices eBook](https://aka.ms/microservicesebook/). + +## Coding Standards + +There are no explicit coding standards so pay attention to the general coding style, that's (mostly) used everywhere. + +However, there's only one **REALLY** important rule: **use spaces for indenting** 😉. + +## Development Process + +In order to help manage community contributions and avoid conflicts, there's a [Development project](https://github.com/dotnet-architecture/eShopOnContainers/projects/3) in this repo, to track assignments to any significant development effort. + +Great but... **what's "significant"**? + +That's not too easy to define and there are no clear criteria right now but, probably, changing "a couple" lines of code in one file would not qualify while changing "a bunch" of files would. + +We'll all be learning in the process so we'll figure it out somehow. + +### General Steps + +1. Issues are managed as usual with the regular issues list, just like any other repo. + +2. Once an issue is marked as a bug, enhancement, new feature or whatever needs development work, it will be labeled as a **backlog-item** and included as the last item in the Backlog project column. + +3. Community members can propose themselves to code an issue. + +4. @CESARDELATORRE/collaborators will prioritize the backlog items and arrange them in the **Backlog** column, so that the items in the top of the list are implemented first. + +5. @CESARDELATORRE/collaborators will review the issues and select the ones approved to begin development with, and move them to the **Approved** column. + +6. Issues in the **Approved** column can be assigned to a **collaborator** or to a **community member** who would then begin working on the issue and submit a PR as usual. + +## Tests + +There's not a tests policy in the project at this moment, but it'll be greatly appreciated if you include them within the [updated test structure](./test/readme.md). + +## Forks and Branches + +All contributions must be submitted as a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/) so you need to [fork this repo](https://help.github.com/articles/fork-a-repo/) on your GitHub account. + +The main branches are **`dev`** and **`master`**: + +- **`dev`**: Contains the latest code **and it is the branch actively developed**. +**All PRs must be against `dev` branch to be considered**. This branch is developed using .NET Core 2.x + +- **`master`**: Synced from time to time from **`dev`**. It contains "stable" code. +(**Keep in mind "stable" does not mean PRODUCTION-READY!**) + +- Any other branch is considered temporary and could be deleted at any time. Do not submit any PR to them! + +## DISCLAIMER - This is not a PRODUCTION-READY TEMPLATE for microservices +eShopOnContainers is a reference application to **showcase architectural patterns** for developing microservices applications on .NET Core. **IT IS NOT A PRODUCTION-READY TEMPLATE** to start real-world application. In fact, the application is in a **permanent beta state**, as it’s also used to test new potentially interesting technologies as they show up. + +Since this is a learning resource, some design decisions have favored simplicity to convey a pattern, over production-grade robustness. + +## Suggestions + +We hope this helps us all to work better and avoid some of the problems/frustrations of working in such a large community. + +We'd also appreciate any comments or ideas to improve this. + diff --git a/NuGet.config b/NuGet.config index da29646ef..0a3819dd2 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,6 +4,9 @@ + + + diff --git a/README.md b/README.md index 4637f13ce..ac5b5f401 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,93 @@ # eShopOnContainers - Microservices Architecture and Containers based Reference Application (**BETA state** - Visual Studio 2017 and CLI environments compatible) Sample .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers. +## Linux Build Status for 'dev' branch + +Dev branch contains the latest "stable" code, and their images are tagged with `:dev` in our [Docker Hub](https://cloud.docker.com/u/eshop/repository/list): + +Api Gateways base image + +[![Api Gateways base image](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/apigws?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=201&branchName=dev) + +Basket API + +[![Basket API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/basket?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=199&branchName=dev) + +Catalog API + +[![Catalog API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/catalog?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=197&branchName=dev) + +Identity API + +[![Identity API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/identity?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=200&branchName=dev) + +Location API + +[![Location API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/location?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=202&branchName=dev) + +Marketing API + +[![Marketing API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/marketing?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=203&branchName=dev) + +Ordering API + +[![Ordering API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/ordering?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=198&branchName=dev) + +Payment API + +[![Payment API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/payment?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=205&branchName=dev) + +Webhooks API + +[![Webhooks API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webhooks?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=207&branchName=dev) + +Web Shopping Aggregator + +[![Web Shopping Aggregator](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/web-shopping-agg?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=206&branchName=dev) + +Mobile Shopping Aggregator + +[![Mobile Shopping Aggregator](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/mobile-shopping-agg?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=204&branchName=dev) + +Webbhooks demo client + +[![Webhooks demo client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webhooks-client?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=208&branchName=dev) + +WebMVC Client + +[![WebMVC Client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webmvc?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=209&branchName=dev) + +WebSPA Client + +[![WebSPA Client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webspa?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=210&branchName=dev) + +Web Status + +[![Web Status](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webstatus?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=211&branchName=dev) + + ## IMPORTANT NOTES! -**The current supported Visual Studio version for eShopOnContainers is Visual Studio 2017 15.7** ([GA/RTM since May 8th 2018](https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes)) or later version. +**You can use either the latest version of Visual Studio or simply Docker CLI and .NET CLI for Windows, Mac and Linux**. **Note for Pull Requests (PRs)**: We accept pull request from the community. When doing it, please do it onto the **DEV branch** which is the consolidated work-in-progress branch. Do not request it onto Master branch, if possible. **NEWS / ANNOUNCEMENTS** Do you want to be up-to-date on .NET Architecture guidance and reference apps like eShopOnContainers? --> Subscribe by "WATCHING" this new GitHub repo: https://github.com/dotnet-architecture/News -## Updated for .NET Core 2.0 "wave" of technologies -eShopOnContainers is updated to .NET Core 2.0 "wave". Not just compilation but also new recommended code in EF Core 2.0, ASP.NET Core 2.0, and other new related versions. +## Updated for .NET Core 2.2 "wave" of technologies +eShopOnContainers is updated to .NET Core 2.x (currently updated to 2.2) "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions. The **dockerfiles** in the solution have also been updated and now support [**Docker Multi-Stage**](https://blogs.msdn.microsoft.com/stevelasker/2017/09/11/net-and-multistage-dockerfiles/) since mid-December 2017. -For a list on the new .NET Core 2.0 related implemented features, see this [blog post](https://blogs.msdn.microsoft.com/dotnet/2017/08/02/microservices-and-docker-containers-architecture-patterns-and-development-guidance/). - >**PLEASE** Read our [branch guide](./branch-guide.md) to know about our branching policy > ### DISCLAIMER -> **IMPORTANT:** The current state of this sample application is **BETA**, because we are constantly evolving towards new released technologies. Therefore, many areas could be improved and change significantly while refactoring current code and implementing new features. Feedback with improvements and pull requests from the community will be highly appreciated and accepted. +> **IMPORTANT:** The current state of this sample application is **BETA**, because we are constantly evolving towards newly released technologies. Therefore, many areas could be improved and change significantly while refactoring the current code and implementing new features. Feedback with improvements and pull requests from the community will be highly appreciated and accepted. > -> This reference application proposes a simplified microservice oriented architecture implementation to introduce technologies like .NET Core with Docker containers through a comprehensive application. The chosen domain is an eShop/eCommerce but simply because it is a well-know domain by most people/developers. -However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core. +> This reference application proposes a simplified microservice oriented architecture implementation to introduce technologies like .NET Core with Docker containers through a comprehensive application. The chosen domain is eShop/eCommerce but simply because it is a well-known domain by most people/developers. +However, this sample application should not be considered as an "eCommerce reference model" at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core. >

For example, the next step after running the solution in the local dev PC and understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Kubernetes in Azure (AKS) or Azure Service Fabric, both environments tested and supported by this solution. -> Additional steps would be to move your databases to HA cloud services (like Azure SQL Database), or switch your EventBus to use Azure Service Bus (instead of bare-bone RabbitMQ) or any other production ready Service Bus in the market. +> Additional steps would be to move your databases to HA cloud services (like Azure SQL Database) or switch your EventBus to use Azure Service Bus (instead of bare-bone RabbitMQ) or any other production-ready Service Bus in the market. ![image](https://user-images.githubusercontent.com/1712635/40397331-059a7ec6-5de7-11e8-8542-a597eca16fef.png) @@ -41,7 +104,7 @@ The architecture proposes a microservice oriented architecture implementation wi > ### Important Note on API Gateways and published APIs > Since April 2018, we have introduced the implementation of the [API Gateway pattern](http://microservices.io/patterns/apigateway.html) and [Backend-For-Front-End (BFF) pattern](https://samnewman.io/patterns/architectural/bff/) in eShopOnContainers architecture, so you can filter and publish simplified APIs and URIs and apply additional security in that tier while hiding/securing the internal microservices to the client apps or outside consumers. These sample API Gateways in eShopOnContainers are based on [Ocelot](https://github.com/ThreeMammals/Ocelot), an OSS lightweight API Gateway solution explained [here](http://threemammals.com/ocelot). The deployed API Gateways are autonomous and can be deployed as your own custom microservices/containers, as it is currently done in eShopOnContainers, so you can test it even in a simple development environment with just Docker engine or deploy it into orchestrators like Kubernetes in AKS or Service Fabric. -> For your production-ready architecture you can either keep using [Ocelot](https://github.com/ThreeMammals/Ocelot) which is simple and easy to use and used in production by significant companies or if you need further functionality and a much richer set of features suittable for commercial APIs, you can also substitute those API Gateways and use [Azure API Management](https://azure.microsoft.com/en-us/services/api-management/) or any other commercial API Gateway, as shown in the following image. +> For your production-ready architecture you can either keep using [Ocelot](https://github.com/ThreeMammals/Ocelot) which is simple and easy to use and used in production by significant companies or if you need further functionality and a much richer set of features suitable for commercial APIs, you can also substitute those API Gateways and use [Azure API Management](https://azure.microsoft.com/en-us/services/api-management/) or any other commercial API Gateway, as shown in the following image.

@@ -58,9 +121,9 @@ The architecture proposes a microservice oriented architecture implementation wi

> ### Important Note on Database Servers/Containers -> In this solution's current configuration for a development environment, the SQL databases are automatically deployed with sample data into a single SQL Server container (a single shared Docker container for SQL databases) so the whole solution can be up and running without any dependency to any cloud or specific server. Each database could also be deployed as a single Docker container, but then you'd need more than 8GB of RAM assigned to Docker in your development machine in order to be able to run 3 SQL Server Docker containers in your Docker Linux host in "Docker for Windows" or "Docker for Mac" development environments. +> In this solution's current configuration for a development environment, the SQL databases are automatically deployed with sample data into a single SQL Server container (a single shared Docker container for SQL databases) so the whole solution can be up and running without any dependency to any cloud or a specific server. Each database could also be deployed as a single Docker container, but then you'd need more than 8GB of RAM assigned to Docker in your development machine in order to be able to run 3 SQL Server Docker containers in your Docker Linux host in "Docker for Windows" or "Docker for Mac" development environments. >

A similar case is defined in regard to Redis cache running as a container for the development environment. Or a No-SQL database (MongoDB) running as a container. ->

However, in a real production environment it is recommended to have your databases (SQL Server, Redis, and the NO-SQL database, in this case) in HA (High Available) services like Azure SQL Database, Redis as a service and Azure CosmosDB instead the MongoDB container (as both systems share the same access protocol). If you want to change to a production configuration, you'll just need to change the connection strings once you have set up the servers in a HA cloud or on-premises. +>

However, in a real production environment it is recommended to have your databases (SQL Server, Redis, and the NO-SQL database, in this case) in HA (High Available) services like Azure SQL Database, Redis as a service and Azure CosmosDB instead the MongoDB container (as both systems share the same access protocol). If you want to change to a production configuration, you'll just need to change the connection strings once you have set up the servers in an HA cloud or on-premises. ## Related documentation and guidance While developing this reference application, we've been creating a reference Guide/eBook focusing on architecting and developing containerized and microservice based .NET Applications (download link available below) which explains in detail how to develop this kind of architectural style (microservices, Docker containers, Domain-Driven Design for certain microservices) plus other simpler architectural styles, like monolithic apps that can also live as Docker containers. @@ -72,18 +135,18 @@ You can download them and start reviewing these Guides/eBooks here: | Architecting & Developing | Containers Lifecycle & CI/CD | App patterns with Xamarin.Forms | | ------------ | ------------| ------------| | | | | -| **Download .PDF** (2nd Edition) | **Download** | **Download** | +| **Download .PDF** (v2.2 Edition) | **Download** | **Download** | Download in other formats (**eReaders** like **MOBI**, **EPUB**) and other eBooks at the [.NET Architecture center](http://dot.net/architecture). Send feedback to [dotnet-architecture-ebooks-feedback@service.microsoft.com](dotnet-architecture-ebooks-feedback@service.microsoft.com) -However, we encourage to download and review the [Architecting and Developing Microservices eBook](https://aka.ms/microservicesebook) because the architectural styles and architectural patterns and technologies explained in the guidance are using this reference application when explaining many pattern implementations, so you'll understand much better the context, design and decisions taken in the current architecture and internal designs. +However, we encourage you to download and review the [Architecting and Developing Microservices eBook](https://aka.ms/microservicesebook) because the architectural styles and architectural patterns and technologies explained in the guide are using this reference application when explaining many pattern implementations, so you'll understand the context, design and decisions taken in the current architecture and internal designs much better. ## Overview of the application code In this repo you can find a sample reference application that will help you to understand how to implement a microservice architecture based application using .NET Core and Docker. -The example business domain or scenario is based on an eShop or eCommerce which is implemented as a multi-container application. Each container is a microservice deployment (like the basket-microservice, catalog-microservice, ordering-microservice and the identity-microservice) which are developed using ASP.NET Core running on .NET Core so they can run either on Linux Containers and Windows Containers. +The example business domain or scenario is based on an eShop or eCommerce which is implemented as a multi-container application. Each container is a microservice deployment (like the basket-microservice, catalog-microservice, ordering-microservice and the identity-microservice) which is developed using ASP.NET Core running on .NET Core so they can run either on Linux Containers and Windows Containers. The screenshot below shows the VS Solution structure for those microservices/containers and client apps. - (*Recommended when getting started*) Open eShopOnContainers-ServicesAndWebApps.sln for a solution containing just the server-side projects related to the microservices and web applications. diff --git a/build/azure-devops/apigws/azure-pipelines.yml b/build/azure-devops/apigws/azure-pipelines.yml new file mode 100644 index 000000000..d2f4708f6 --- /dev/null +++ b/build/azure-devops/apigws/azure-pipelines.yml @@ -0,0 +1,50 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/ApiGateways/* + - k8s/helm/apigwmm/* + - k8s/helm/apigwms/* + - k8s/helm/apigwwm/* + - k8s/helm/apigwws/* + exclude: + - src/ApiGateways/Mobile.Bff.Shopping/aggregator/* + - src/ApiGateways/Web.Bff.Shopping/aggregator/* +steps: +- task: DockerCompose@0 + displayName: Compose build apigws + inputs: + dockerComposeCommand: 'build mobileshoppingapigw mobilemarketingapigw webshoppingapigw webmarketingapigw' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push apigws + inputs: + dockerComposeCommand: 'push mobileshoppingapigw mobilemarketingapigw webshoppingapigw webmarketingapigw' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/basket-api/azure-pipelines.yml b/build/azure-devops/basket-api/azure-pipelines.yml new file mode 100644 index 000000000..6d94c5918 --- /dev/null +++ b/build/azure-devops/basket-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Basket/* + - k8s/helm/basket-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build basket + inputs: + dockerComposeCommand: 'build basket.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push basket + inputs: + dockerComposeCommand: 'push basket.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/catalog-api/azure-pipelines.yml b/build/azure-devops/catalog-api/azure-pipelines.yml new file mode 100644 index 000000000..d277d4777 --- /dev/null +++ b/build/azure-devops/catalog-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Catalog/* + - k8s/helm/catalog-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build catalog + inputs: + dockerComposeCommand: 'build catalog.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push catalog + inputs: + dockerComposeCommand: 'push catalog.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/identity-api/azure-pipelines.yml b/build/azure-devops/identity-api/azure-pipelines.yml new file mode 100644 index 000000000..454c03d16 --- /dev/null +++ b/build/azure-devops/identity-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Identity/* + - k8s/helm/identity-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build identity + inputs: + dockerComposeCommand: 'build identity.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push identity + inputs: + dockerComposeCommand: 'push identity.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/location-api/azure-pipelines.yml b/build/azure-devops/location-api/azure-pipelines.yml new file mode 100644 index 000000000..ab3d31b3f --- /dev/null +++ b/build/azure-devops/location-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Location/* + - k8s/helm/locations-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build locations + inputs: + dockerComposeCommand: 'build locations.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push locations + inputs: + dockerComposeCommand: 'push locations.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/marketing-api/azure-pipelines.yml b/build/azure-devops/marketing-api/azure-pipelines.yml new file mode 100644 index 000000000..193a0cccf --- /dev/null +++ b/build/azure-devops/marketing-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Marketing/* + - k8s/helm/marketing-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build marketing + inputs: + dockerComposeCommand: 'build marketing.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push marketing + inputs: + dockerComposeCommand: 'push marketing.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml b/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml new file mode 100644 index 000000000..6fb0018a1 --- /dev/null +++ b/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml @@ -0,0 +1,44 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/ApiGateways/Mobile.Bff.Shopping/aggregator/* + - k8s/helm/mobileshoppingagg/* +steps: +- task: DockerCompose@0 + displayName: Compose build mobileshoppingagg + inputs: + dockerComposeCommand: 'build mobileshoppingagg' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push mobileshoppingagg + inputs: + dockerComposeCommand: 'push mobileshoppingagg' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/ordering-api/azure-pipelines.yml b/build/azure-devops/ordering-api/azure-pipelines.yml new file mode 100644 index 000000000..ef0b17a32 --- /dev/null +++ b/build/azure-devops/ordering-api/azure-pipelines.yml @@ -0,0 +1,47 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Ordering/* + - k8s/helm/ordering-api/* + - k8s/helm/ordering-backgroundtasks/* + - k8s/helm/ordering-signalrhub/* +steps: +- task: DockerCompose@0 + displayName: Compose build ordering + inputs: + dockerComposeCommand: 'build ordering.api ordering.backgroundtasks ordering.signalrhub' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push ordering + inputs: + dockerComposeCommand: 'push ordering.api ordering.backgroundtasks ordering.signalrhub' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/payment-api/azure-pipelines.yml b/build/azure-devops/payment-api/azure-pipelines.yml new file mode 100644 index 000000000..8518c8841 --- /dev/null +++ b/build/azure-devops/payment-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Payment/* + - k8s/helm/payment-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build payment + inputs: + dockerComposeCommand: 'build payment.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push payment + inputs: + dockerComposeCommand: 'push payment.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/readme.md b/build/azure-devops/readme.md new file mode 100644 index 000000000..b7216d4de --- /dev/null +++ b/build/azure-devops/readme.md @@ -0,0 +1,5 @@ +# Azure Devops build definitions + +This folder contains the Azure Devops build definitions in YAML format. Each folder contains one `azure-pipelines.yml` that contains the build definition for one microservice (usually a Docker image, but some microservices generates more than one Docker image). + +For more information about YAML builds read the [Azure DevOps documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started-yaml?view=azure-devops). \ No newline at end of file diff --git a/build/azure-devops/web-shopping-agg/azure-pipelines.yml b/build/azure-devops/web-shopping-agg/azure-pipelines.yml new file mode 100644 index 000000000..70a4df950 --- /dev/null +++ b/build/azure-devops/web-shopping-agg/azure-pipelines.yml @@ -0,0 +1,44 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/ApiGateways/Web.Bff.Shopping/aggregator/* + - k8s/helm/webshoppingagg/* +steps: +- task: DockerCompose@0 + displayName: Compose build webshoppingagg + inputs: + dockerComposeCommand: 'build webshoppingagg' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webshoppingagg + inputs: + dockerComposeCommand: 'push webshoppingagg' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/webhooks-api/azure-pipelines.yml b/build/azure-devops/webhooks-api/azure-pipelines.yml new file mode 100644 index 000000000..b48948111 --- /dev/null +++ b/build/azure-devops/webhooks-api/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Services/Webhooks/* + - k8s/helm/webhooks-api/* +steps: +- task: DockerCompose@0 + displayName: Compose build webhooks + inputs: + dockerComposeCommand: 'build webhooks.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webhooks + inputs: + dockerComposeCommand: 'push webhooks.api' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/webhooks-client/azure-pipelines.yml b/build/azure-devops/webhooks-client/azure-pipelines.yml new file mode 100644 index 000000000..71e3bbe16 --- /dev/null +++ b/build/azure-devops/webhooks-client/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Web/WebhookClient/* + - k8s/helm/webhooks-web/* +steps: +- task: DockerCompose@0 + displayName: Compose build webhooks.client + inputs: + dockerComposeCommand: 'build webhooks.client' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webhooks.client + inputs: + dockerComposeCommand: 'push webhooks.client' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/webmvc/azure-pipelines.yml b/build/azure-devops/webmvc/azure-pipelines.yml new file mode 100644 index 000000000..66b8518fa --- /dev/null +++ b/build/azure-devops/webmvc/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Web/WebMVC/* + - k8s/helm/webmvc/* +steps: +- task: DockerCompose@0 + displayName: Compose build webmvc + inputs: + dockerComposeCommand: 'build webmvc' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webmvc + inputs: + dockerComposeCommand: 'push webmvc' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/webspa/azure-pipelines.yml b/build/azure-devops/webspa/azure-pipelines.yml new file mode 100644 index 000000000..eee8cd25d --- /dev/null +++ b/build/azure-devops/webspa/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Web/WebSPA/* + - k8s/helm/webspa/* +steps: +- task: DockerCompose@0 + displayName: Compose build webspa + inputs: + dockerComposeCommand: 'build webspa' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webspa + inputs: + dockerComposeCommand: 'push webspa' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/build/azure-devops/webstatus/azure-pipelines.yml b/build/azure-devops/webstatus/azure-pipelines.yml new file mode 100644 index 000000000..311c457e2 --- /dev/null +++ b/build/azure-devops/webstatus/azure-pipelines.yml @@ -0,0 +1,45 @@ +pool: + vmImage: 'ubuntu-16.04' +variables: + registryEndpoint: eshop-registry +trigger: + branches: + include: + - master + - dev + paths: + include: + - src/BuildingBlocks/* + - src/Web/WebStatus/* + - k8s/helm/webstatus/* +steps: +- task: DockerCompose@0 + displayName: Compose build webstatus + inputs: + dockerComposeCommand: 'build webstatus' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: DockerCompose@0 + displayName: Compose push webstatus + inputs: + dockerComposeCommand: 'push webstatus' + containerregistrytype: Container Registry + dockerRegistryEndpoint: $(registryEndpoint) + dockerComposeFile: docker-compose.yml + qualifyImageNames: true + projectName: "" + dockerComposeFileArgs: | + TAG=$(Build.SourceBranchName) +- task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)/k8s/helm + targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm +- task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm + artifactName: helm diff --git a/cli-windows/build-images.ps1 b/cli-windows/build-images.ps1 index d454f3a14..bfd6e478b 100644 --- a/cli-windows/build-images.ps1 +++ b/cli-windows/build-images.ps1 @@ -8,4 +8,4 @@ if ([string]::IsNullOrEmpty($imageTag)) { Write-Host "Building images with tag $imageTag" -ForegroundColor Yellow $env:TAG=$imageTag -docker-compose -f "$scriptPath\..\docker-compose.yml" build \ No newline at end of file +docker-compose -f "$scriptPath\..\docker-compose.yml" -f "$scriptPath\..\docker-compose.windows.yml" build \ No newline at end of file diff --git a/cli-windows/start-windows-containers.ps1 b/cli-windows/start-windows-containers.ps1 index 85a182603..31e265322 100644 --- a/cli-windows/start-windows-containers.ps1 +++ b/cli-windows/start-windows-containers.ps1 @@ -23,10 +23,11 @@ if ($buildBits) { $env:ESHOP_EXTERNAL_DNS_NAME_OR_IP = "10.0.75.1" $env:ESHOP_AZURE_STORAGE_CATALOG_URL ="http://10.0.75.1:5101/api/v1/catalog/items/[0]/pic/" $env:ESHOP_AZURE_STORAGE_MARKETING_URL ="http://10.0.75.1:5110/api/v1/campaigns/[0]/pic/" +$env:ESHOP_OCELOT_VOLUME_SPEC ="C:\app\configuration" if (-Not $customEventBusLoginPassword) { - docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.override.windows.yml" up + docker-compose -f "$rootPath\docker-compose.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.windows.yml" -f "$rootPath\docker-compose.override.windows.yml" up } else { - docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" up + docker-compose -f "$rootPath\docker-compose.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.windows.yml" up } diff --git a/deploy/az/servicebus/readme.md b/deploy/az/servicebus/readme.md index 16da4c7b2..886b3ec60 100644 --- a/deploy/az/servicebus/readme.md +++ b/deploy/az/servicebus/readme.md @@ -8,7 +8,7 @@ The ARM template `sbusdeploy.json` and its parameter file (`sbusdeploy.parameter ## Editing sbusdeploy.parameters.json file -You can edit the `sbusdeploy.parameters.parameters.json` file to set your values, but is not needed. The only parameter than can +You can edit the `sbusdeploy.parameters.json` file to set your values, but is not needed. The only parameter than can be set is: 1. `namespaceprefix` is a string that is used to create the namespace. ARM script creates unique values by appending a unique string to this parameter value, so you can leave the default value. @@ -21,4 +21,4 @@ i. e. if you are in windows, to deploy servicebus in a new resourcegroup located ``` create-resources.cmd servicebus\sbusdeploy newResourceGroup -c westus -``` \ No newline at end of file +``` diff --git a/docker-compose-tests.override.yml b/docker-compose-tests.override.yml new file mode 100644 index 000000000..8705e703f --- /dev/null +++ b/docker-compose-tests.override.yml @@ -0,0 +1,247 @@ +version: '3.4' + +services: + rabbitmq-test: + ports: + - "15672:15672" + - "5672:5672" + + sql-data-test: + environment: + - SA_PASSWORD=Pass@word + - ACCEPT_EULA=Y + ports: + - "5433:1433" + + nosql-data-test: + ports: + - "27017:27017" + + basket-data-test: + ports: + - "6379:6379" + + identity-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104 + - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback + - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} + - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 + - LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109 + - MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 + - BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 + - OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102 + - MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120 + - WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5121 + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5105:80" + + basket-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket-data-test} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5103:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/basket-test-results.xml + + basket-api-unit-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket-data-test} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5113:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/basket-unit-test-results.xml + + catalog-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME} + - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - AzureStorageEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5101:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/catalog-test-results.xml + + catalog-api-unit-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME} + - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - AzureStorageEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5191:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/catalog-unit-test-results.xml + + ordering-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - CheckUpdateTime=30000 + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5102:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/ordering-test-results.xml + + ordering-api-unit-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - CheckUpdateTime=30000 + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5112:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/ordering-unit-test-results.xml + + marketing-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} + - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql-data-test} + - MongoDatabase=MarketingDb + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING_URL:-http://localhost:5110/api/v1/campaigns/[0]/pic/} + - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_MARKETING_NAME} + - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_MARKETING_KEY} + - AzureServiceBusEnabled=False + - AzureStorageEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5110:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/marketing-test-results.xml + + payment-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5108:80" + + locations-api-test: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql-data-test} + - Database=LocationsDb + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5109:80" + entrypoint: + - dotnet + - test + - --logger + - trx;LogFileName=/tests/locations-test-results.xml \ No newline at end of file diff --git a/docker-compose-tests.yml b/docker-compose-tests.yml new file mode 100644 index 000000000..7794d1a0e --- /dev/null +++ b/docker-compose-tests.yml @@ -0,0 +1,130 @@ +version: '3.4' + +services: + rabbitmq-test: + image: rabbitmq:3-management-alpine + + basket-data-test: + image: redis:alpine + + sql-data-test: + image: microsoft/mssql-server-linux:2017-latest + + nosql-data-test: + image: mongo + + identity-api-test: + image: ${REGISTRY:-eshop}/identity-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Identity/Identity.API/Dockerfile + depends_on: + - sql-data-test + + basket-api-test: + image: ${REGISTRY:-eshop}/basket-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Basket/Basket.API/Dockerfile + target: functionaltest + depends_on: + - basket-data-test + - identity-api-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + basket-api-unit-test: + image: ${REGISTRY:-eshop}/basket-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Basket/Basket.API/Dockerfile + target: unittest + depends_on: + - basket-data-test + - identity-api-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + catalog-api-test: + image: ${REGISTRY:-eshop}/catalog-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Catalog/Catalog.API/Dockerfile + target: functionaltest + depends_on: + - sql-data-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + catalog-api-unit-test: + image: ${REGISTRY:-eshop}/catalog-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Catalog/Catalog.API/Dockerfile + target: unittest + depends_on: + - sql-data-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + ordering-api-test: + image: ${REGISTRY:-eshop}/ordering-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Ordering/Ordering.API/Dockerfile + target: functionaltest + depends_on: + - sql-data-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + ordering-api-unit-test: + image: ${REGISTRY:-eshop}/ordering-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Ordering/Ordering.API/Dockerfile + target: unittest + depends_on: + - sql-data-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + marketing-api-test: + image: ${REGISTRY:-eshop}/marketing-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Marketing/Marketing.API/Dockerfile + target: functionaltest + depends_on: + - sql-data-test + - nosql-data-test + - identity-api-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests + + payment-api-test: + image: ${REGISTRY:-eshop}/payment-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Payment/Payment.API/Dockerfile + depends_on: + - rabbitmq-test + + locations-api-test: + image: ${REGISTRY:-eshop}/locations-api-test:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Location/Locations.API/Dockerfile + target: functionaltest + depends_on: + - nosql-data-test + - rabbitmq-test + volumes: + - ${BUILD_ARTIFACTSTAGINGDIRECTORY:-./tests-results/}:/tests \ No newline at end of file diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml deleted file mode 100644 index cdcd6f56b..000000000 --- a/docker-compose-windows.yml +++ /dev/null @@ -1,138 +0,0 @@ -version: '3.4' - -services: - basket.api: - image: eshop/basket.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Basket/Basket.API/Dockerfile - depends_on: - - basket.data - - identity.api - - rabbitmq - - catalog.api: - image: eshop/catalog.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Catalog/Catalog.API/Dockerfile - depends_on: - - sql.data - - rabbitmq - - identity.api: - image: eshop/identity.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Identity/Identity.API/Dockerfile - depends_on: - - sql.data - - ordering.api: - image: eshop/ordering.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Ordering/Ordering.API/Dockerfile - depends_on: - - sql.data - - rabbitmq - - ordering.backgroundtasks: - image: eshop/ordering.backgroundtasks-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile - depends_on: - - sql.data - - rabbitmq - - ordering.signalrhub: - image: eshop/ordering.signalrhub:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Ordering/Ordering.SignalrHub/Dockerfile - depends_on: - - sql.data - - identity.api - - rabbitmq - - marketing.api: - image: eshop/marketing.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Marketing/Marketing.API/Dockerfile - depends_on: - - sql.data - - nosql.data - - identity.api - - rabbitmq - - webspa: - image: eshop/webspa-win:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebSPA/Dockerfile - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webmvc: - image: eshop/webmvc-win:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebMVC/Dockerfile - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webstatus: - image: eshop/webstatus-win:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebStatus/Dockerfile - - payment.api: - image: eshop/payment.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Payment/Payment.API/Dockerfile - depends_on: - - rabbitmq - - locations.api: - image: eshop/locations.api-win:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Location/Locations.API/Dockerfile - depends_on: - - nosql.data - - rabbitmq - - sql.data: - image: microsoft/mssql-server-windows-developer - - nosql.data: - image: mongo:windowsservercore - - basket.data: - image: redis:nanoserver - ports: - - "6379:6379" - - rabbitmq: - image: spring2/rabbitmq - ports: - - "15672:15672" - - "5672:5672" - -networks: - default: - external: - name: nat - diff --git a/docker-compose.override.windows.yml b/docker-compose.override.windows.yml index 0d31493e6..dcaac7c45 100644 --- a/docker-compose.override.windows.yml +++ b/docker-compose.override.windows.yml @@ -37,11 +37,6 @@ services: - EventBusUserName=admin - EventBusPassword=password - ordering.api: - environment: - - EventBusUserName=admin - - EventBusPassword=password - ordering.backgroundtasks: environment: - EventBusUserName=admin @@ -58,6 +53,6 @@ services: - EventBusPassword=password ordering.signalrhub: - environment: + environment: - EventBusUserName=admin - - EventBusPassword=password \ No newline at end of file + - EventBusPassword=password diff --git a/docker-compose.override.yml b/docker-compose.override.yml index d523b328a..e59a9a2e6 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -7,7 +7,54 @@ version: '3.4' # An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance. services: - + seq: + environment: + - ACCEPT_EULA=Y + ports: + - "5340:80" + + sql.data: + environment: + - SA_PASSWORD=Pass@word + - ACCEPT_EULA=Y + ports: + - "5433:1433" # Important: In a production environment your should remove the external port + + nosql.data: + ports: + - "27017:27017" # Important: In a production environment your should remove the external port + + basket.data: + ports: + - "6379:6379" # Important: In a production environment your should remove the external port + + rabbitmq: + ports: + - "15672:15672" # Important: In a production environment your should remove the external port + - "5672:5672" # Important: In a production environment your should remove the external port + + identity.api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104 + - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always + - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} + - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110. + - LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109 + - MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 + - BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 + - OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102 + - MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120 + - WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5121 + - WebhooksApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5113 + - WebhooksWebClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5114 + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5105:80" + basket.api: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -47,26 +94,6 @@ services: - "5101:80" # Important: In a production environment your should remove the external port (5101) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). - identity.api: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104 - - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always - - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} - - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110. - - LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109 - - MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 - - BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 - - OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102 - - MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120 - - WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5121 - - UseCustomizationData=True - - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - - OrchestratorType=${ORCHESTRATOR_TYPE} - ports: - - "5105:80" - ordering.api: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -80,7 +107,6 @@ services: - UseCustomizationData=True - AzureServiceBusEnabled=False - CheckUpdateTime=30000 - - GracePeriodTime=1 - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - OrchestratorType=${ORCHESTRATOR_TYPE} - UseLoadTest=${USE_LOADTEST:-False} @@ -132,66 +158,6 @@ services: - "5110:80" # Important: In a production environment your should remove the external port (5110) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). - webspa: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - - PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 - - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203 - - CatalogUrlHC=http://catalog.api/hc - - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrlHC=http://basket.api/hc - - MarketingUrlHC=http://marketing.api/hc - - PaymentUrlHC=http://payment.api/hc - - UseCustomizationData=True - - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - - OrchestratorType=${ORCHESTRATOR_TYPE} - - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 - ports: - - "5104:80" - - webmvc: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - PurchaseUrl=http://webshoppingapigw - - IdentityUrl=http://10.0.75.1:5105 # Local Mac: Use http://docker.for.mac.localhost:5105 || Local Windows: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. || #Remote access: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. - - MarketingUrl=http://webmarketingapigw - - CatalogUrlHC=http://catalog.api/hc - - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrlHC=http://basket.api/hc - - MarketingUrlHC=http://marketing.api/hc - - PaymentUrlHC=http://payment.api/hc - - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 - - UseCustomizationData=True - - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - - OrchestratorType=${ORCHESTRATOR_TYPE} - - UseLoadTest=${USE_LOADTEST:-False} - ports: - - "5100:80" - - webstatus: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://catalog.api/hc - - OrderingUrl=http://ordering.api/hc - - OrderingBackgroundTasksUrl=http://ordering.backgroundtasks/hc - - BasketUrl=http://basket.api/hc - - IdentityUrl=http://identity.api/hc - - LocationsUrl=http://locations.api/hc - - MarketingUrl=http://marketing.api/hc - - PaymentUrl=http://payment.api/hc - - mvc=http://webmvc/hc - - spa=http://webspa/hc - - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - - OrchestratorType=${ORCHESTRATOR_TYPE} - ports: - - "5107:80" - payment.api: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -224,63 +190,87 @@ services: ports: - "5109:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). - - - sql.data: + webhooks.api: environment: - - SA_PASSWORD=Pass@word - - ACCEPT_EULA=Y - ports: - - "5433:1433" # Important: In a production environment your should remove the external port - - nosql.data: - ports: - - "27017:27017" # Important: In a production environment your should remove the external port - - basket.data: - ports: - - "6379:6379" # Important: In a production environment your should remove the external port - - rabbitmq: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_WEBHOOKS_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.WebhooksDb;User Id=sa;Password=Pass@word} + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - IdentityUrl=http://identity.api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 ports: - - "15672:15672" # Important: In a production environment your should remove the external port - - "5672:5672" # Important: In a production environment your should remove the external port + - "5113:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes. + # The API Gateway redirects and access through the internal port (80). mobileshoppingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - urls__basket=http://basket.api + - urls__catalog=http://catalog.api + - urls__orders=http://ordering.api + - urls__identity=http://identity.api + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5200:80" volumes: - - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration - + - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} + mobilemarketingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5201:80" volumes: - - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration + - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} webshoppingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5202:80" volumes: - - ./src/ApiGateways/Web.Bff.Shopping/apigw:/app/configuration + - ./src/ApiGateways/Web.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} webmarketingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5203:80" volumes: - - ./src/ApiGateways/Web.Bff.Marketing/apigw:/app/configuration + - ./src/ApiGateways/Web.Bff.Marketing/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} mobileshoppingagg: environment: @@ -289,6 +279,13 @@ services: - urls__catalog=http://catalog.api - urls__orders=http://ordering.api - urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5120:80" # Important: In a production environment your should remove the external port (5120) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). @@ -300,9 +297,17 @@ services: - urls__catalog=http://catalog.api - urls__orders=http://ordering.api - urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - CatalogUrlHC=http://catalog.api/hc + - OrderingUrlHC=http://ordering.api/hc + - IdentityUrlHC=http://identity.api/hc + - BasketUrlHC=http://basket.api/hc + - MarketingUrlHC=http://marketing.api/hc + - PaymentUrlHC=http://payment.api/hc + - LocationUrlHC=http://locations.api/hc ports: - "5121:80" # Important: In a production environment your should remove the external port (5121) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). + ordering.signalrhub: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -317,3 +322,92 @@ services: ports: - "5112:80" + webstatus: + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://0.0.0.0:80 + - HealthChecks-UI__HealthChecks__1__Name=WebMVC HTTP Check + - HealthChecks-UI__HealthChecks__1__Uri=http://webmvc/hc + - HealthChecks-UI__HealthChecks__2__Name=WebSPA HTTP Check + - HealthChecks-UI__HealthChecks__2__Uri=http://webspa/hc + - HealthChecks-UI__HealthChecks__3__Name=Web Shopping Aggregator GW HTTP Check + - HealthChecks-UI__HealthChecks__3__Uri=http://webshoppingagg/hc + - HealthChecks-UI__HealthChecks__4__Name=Mobile Shopping Aggregator HTTP Check + - HealthChecks-UI__HealthChecks__4__Uri=http://mobileshoppingagg/hc + - HealthChecks-UI__HealthChecks__5__Name=Mobile Shopping API GW HTTP Check + - HealthChecks-UI__HealthChecks__5__Uri=http://mobileshoppingapigw/hc + - HealthChecks-UI__HealthChecks__6__Name=Mobile Marketing API GW HTTP Check + - HealthChecks-UI__HealthChecks__6__Uri=http://mobilemarketingapigw/hc + - HealthChecks-UI__HealthChecks__7__Name=Web Shopping API GW HTTP Check + - HealthChecks-UI__HealthChecks__7__Uri=http://webshoppingapigw/hc + - HealthChecks-UI__HealthChecks__8__Name=Web Marketing API GW HTTP Check + - HealthChecks-UI__HealthChecks__8__Uri=http://webmarketingapigw/hc + - HealthChecks-UI__HealthChecks__9__Name=Ordering HTTP Check + - HealthChecks-UI__HealthChecks__9__Uri=http://ordering.api/hc + - HealthChecks-UI__HealthChecks__10__Name=Ordering HTTP Background Check + - HealthChecks-UI__HealthChecks__10__Uri=http://ordering.backgroundtasks/hc + - HealthChecks-UI__HealthChecks__11__Name=Basket HTTP Check + - HealthChecks-UI__HealthChecks__11__Uri=http://basket.api/hc + - HealthChecks-UI__HealthChecks__12__Name=Catalog HTTP Check + - HealthChecks-UI__HealthChecks__12__Uri=http://catalog.api/hc + - HealthChecks-UI__HealthChecks__13__Name=Identity HTTP Check + - HealthChecks-UI__HealthChecks__13__Uri=http://identity.api/hc + - HealthChecks-UI__HealthChecks__14__Name=Marketing HTTP Check + - HealthChecks-UI__HealthChecks__14__Uri=http://marketing.api/hc + - HealthChecks-UI__HealthChecks__15__Name=Locations HTTP Check + - HealthChecks-UI__HealthChecks__15__Uri=http://locations.api/hc + - HealthChecks-UI__HealthChecks__16__Name=Payments HTTP Check + - HealthChecks-UI__HealthChecks__16__Uri=http://payment.api/hc + - HealthChecks-UI__HealthChecks__17__Name=Ordering SignalRHub HTTP Check + - HealthChecks-UI__HealthChecks__17__Uri=http://ordering.signalrhub/hc + - OrderingBackgroundTasksUrl=http://ordering.backgroundtasks/hc + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5107:80" + + webspa: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. + - PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203 + - PurchaseUrlHC=http://webshoppingapigw/hc + - MarketingUrlHC=http://webmarketingapigw/hc + - IdentityUrlHC=http://identity.api/hc + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + ports: + - "5104:80" + + webmvc: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - PurchaseUrl=http://webshoppingapigw + - IdentityUrl=http://10.0.75.1:5105 # Local Mac: Use http://docker.for.mac.localhost:5105 || Local Windows: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. || #Remote access: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. + - MarketingUrl=http://webmarketingapigw + - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + - IdentityUrlHC=http://identity.api/hc + - PurchaseUrlHC=http://webshoppingapigw/hc + - MarketingUrlHC=http://webmarketingapigw/hc + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5100:80" + + webhooks.client: + environment: + - ASPNETCORE_URLS=http://0.0.0.0:80 + - Token=6168DB8D-DC58-4094-AF24-483278923590 # Webhooks are registered with this token (any value is valid) but the client won't check it + - IdentityUrl=http://10.0.75.1:5105 + - CallBackUrl=http://localhost:5114 + - WebhooksUrl=http://webhooks.api + - SelfUrl=http://webhooks.client/ + ports: + - "5114:80" \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 06dcbde6f..4bf465565 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -85,7 +85,6 @@ services: - UseCustomizationData=True - AzureServiceBusEnabled=False - CheckUpdateTime=30000 - - GracePeriodTime=1 - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - OrchestratorType=${ORCHESTRATOR_TYPE} - UseLoadTest=${USE_LOADTEST:-False} diff --git a/docker-compose.windows.yml b/docker-compose.windows.yml new file mode 100644 index 000000000..afc7e4e91 --- /dev/null +++ b/docker-compose.windows.yml @@ -0,0 +1,39 @@ +# This file contains specific services build and images for Windows Containers. +# +# MUST be used alongside "docker-compose.yml" in all windows container commands + +version: '3.4' + +services: + sql.data: + image: microsoft/mssql-server-windows-developer + + nosql.data: + image: mongo:windowsservercore + + basket.data: + image: redis:nanoserver + + rabbitmq: + image: spring2/rabbitmq + + identity.api: + build: + args: + NODE_IMAGE: stefanscherer/node-windows:8.11 + + webspa: + build: + args: + NODE_IMAGE: stefanscherer/node-windows:8.11 + + webmvc: + build: + args: + NODE_IMAGE: stefanscherer/node-windows:8.11 + + +networks: + default: + external: + name: nat \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 414d9a1ef..55d5b10e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,31 @@ version: '3.4' services: + seq: + image: datalust/seq:latest + + sql.data: + image: microsoft/mssql-server-linux:2017-latest + + nosql.data: + image: mongo + + basket.data: + image: redis:alpine + + rabbitmq: + image: rabbitmq:3-management-alpine + + identity.api: + image: ${REGISTRY:-eshop}/identity.api:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Identity/Identity.API/Dockerfile + depends_on: + - sql.data basket.api: - image: eshop/basket.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/basket.api:${TAG:-latest} build: context: . dockerfile: src/Services/Basket/Basket.API/Dockerfile @@ -13,7 +35,7 @@ services: - rabbitmq catalog.api: - image: eshop/catalog.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/catalog.api:${TAG:-latest} build: context: . dockerfile: src/Services/Catalog/Catalog.API/Dockerfile @@ -21,16 +43,8 @@ services: - sql.data - rabbitmq - identity.api: - image: eshop/identity.api:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Identity/Identity.API/Dockerfile - depends_on: - - sql.data - ordering.api: - image: eshop/ordering.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/ordering.api:${TAG:-latest} build: context: . dockerfile: src/Services/Ordering/Ordering.API/Dockerfile @@ -39,7 +53,7 @@ services: - rabbitmq ordering.backgroundtasks: - image: eshop/ordering.backgroundtasks:${TAG:-latest} + image: ${REGISTRY:-eshop}/ordering.backgroundtasks:${TAG:-latest} build: context: . dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile @@ -48,7 +62,7 @@ services: - rabbitmq marketing.api: - image: eshop/marketing.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/marketing.api:${TAG:-latest} build: context: . dockerfile: src/Services/Marketing/Marketing.API/Dockerfile @@ -58,46 +72,16 @@ services: - identity.api - rabbitmq - webspa: - image: eshop/webspa:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebSPA/Dockerfile - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webmvc: - image: eshop/webmvc:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebMVC/Dockerfile - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webstatus: - image: eshop/webstatus:${TAG:-latest} - build: - context: . - dockerfile: src/Web/WebStatus/Dockerfile - payment.api: - image: eshop/payment.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/payment.api:${TAG:-latest} build: context: . dockerfile: src/Services/Payment/Payment.API/Dockerfile depends_on: - rabbitmq - + locations.api: - image: eshop/locations.api:${TAG:-latest} + image: ${REGISTRY:-eshop}/locations.api:${TAG:-latest} build: context: . dockerfile: src/Services/Location/Locations.API/Dockerfile @@ -105,57 +89,149 @@ services: - nosql.data - rabbitmq - sql.data: - image: microsoft/mssql-server-linux:2017-latest - - nosql.data: - image: mongo - - basket.data: - image: redis:alpine - - rabbitmq: - image: rabbitmq:3-management-alpine + webhooks.api: + image: ${REGISTRY:-eshop}/webhooks.api:${TAG:-latest} + build: + context: . + dockerfile: src/Services/Webhooks/Webhooks.API/Dockerfile + depends_on: + - sql.data mobileshoppingapigw: - image: eshop/ocelotapigw:${TAG:-latest} + image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile - + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api + mobilemarketingapigw: - image: eshop/ocelotapigw:${TAG:-latest} + image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile - + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api + webshoppingapigw: - image: eshop/ocelotapigw:${TAG:-latest} + image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api webmarketingapigw: - image: eshop/ocelotapigw:${TAG:-latest} + image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api mobileshoppingagg: - image: eshop/mobileshoppingagg:${TAG:-latest} + image: ${REGISTRY:-eshop}/mobileshoppingagg:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api webshoppingagg: - image: eshop/webshoppingagg:${TAG:-latest} + image: ${REGISTRY:-eshop}/webshoppingagg:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api ordering.signalrhub: - image: eshop/ordering.signalrhub:${TAG:-latest} + image: ${REGISTRY:-eshop}/ordering.signalrhub:${TAG:-latest} build: context: . dockerfile: src/Services/Ordering/Ordering.SignalrHub/Dockerfile + depends_on: + - nosql.data + - sql.data + - identity.api + - rabbitmq + - ordering.api + - marketing.api + - catalog.api + - basket.api + webstatus: + image: ${REGISTRY:-eshop}/webstatus:${TAG:-latest} + build: + context: . + dockerfile: src/Web/WebStatus/Dockerfile + + webspa: + image: ${REGISTRY:-eshop}/webspa:${TAG:-latest} + build: + context: . + dockerfile: src/Web/WebSPA/Dockerfile +# depends_on: +# - webshoppingagg +# - webshoppingapigw +# - webmarketingapigw + + webmvc: + image: ${REGISTRY:-eshop}/webmvc:${TAG:-latest} + build: + context: . + dockerfile: src/Web/WebMVC/Dockerfile + depends_on: + - webshoppingagg + - webshoppingapigw + - webmarketingapigw + + webhooks.client: + image: ${REGISTRY:-eshop}/webhooks.client:${TAG:-latest} + build: + context: . + dockerfile: src/Web/WebhookClient/Dockerfile + depends_on: + - webhooks.api \ No newline at end of file diff --git a/docker-scripts/linux/install-node.sh b/docker-scripts/linux/install-node.sh new file mode 100644 index 000000000..73407aae9 --- /dev/null +++ b/docker-scripts/linux/install-node.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +export NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60 +curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \ + && echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \ + && tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \ + && rm nodejs.tar.gz \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs diff --git a/docker-scripts/win/install-node.cmd b/docker-scripts/win/install-node.cmd new file mode 100644 index 000000000..eaa4e356c --- /dev/null +++ b/docker-scripts/win/install-node.cmd @@ -0,0 +1,4 @@ +set NODE_VERSION=8.11.1 +curl -SL "https://nodejs.org/dist/v%NODE_VERSION%/node-v%NODE_VERSION%-win-x64.zip" --output nodejs.zip +tar -xf nodejs.zip -C c:\ +setx PATH "%PATH%;c:\node-v%NODE_VERSION%-win-x64" \ No newline at end of file diff --git a/docs/Decks/BRK3175_CesarDeIaTorre.pptx b/docs/Decks/BRK3175_CesarDeIaTorre.pptx new file mode 100644 index 000000000..e04d7338e Binary files /dev/null and b/docs/Decks/BRK3175_CesarDeIaTorre.pptx differ diff --git a/docs/Decks/eShopOnContainers-Architecture-v2.1.pptx b/docs/Decks/eShopOnContainers-Architecture-v2.1.pptx new file mode 100644 index 000000000..52398f823 Binary files /dev/null and b/docs/Decks/eShopOnContainers-Architecture-v2.1.pptx differ diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln index f127af6d9..447b73073 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/eShopOnContainers-ServicesAndWebApps.sln @@ -26,7 +26,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ordering", "Ordering", "{0B EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A857AD10-40FF-4303-BEC2-FF1C58D5735E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{EF0337F2-ED00-4643-89FD-EE10863F1870}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServicesTests", "ServicesTests", "{EF0337F2-ED00-4643-89FD-EE10863F1870}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{24CD3B53-141E-4A07-9B0D-796641E1CF78}" EndProject @@ -42,16 +42,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebMVC", "src\Web\WebMVC\We EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "src\Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\UnitTest\UnitTest.csproj", "{7796F5D8-31FC-45A4-B673-19DE5BA194CF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "test\Services\IntegrationTests\IntegrationTests.csproj", "{5B810E3D-112E-4857-B197-F09D2FD41E27}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "test\Services\FunctionalTests\FunctionalTests.csproj", "{CFE2FACB-4538-4B99-8A10-306F3882952D}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{DB0EFB20-B024-4E5E-A75C-52143C131D25}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}" @@ -62,24 +56,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\Bui EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{A81ECBC2-6B00-4DCD-8388-469174033379}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj", "{942ED6E8-0050-495F-A0EA-01E97F63760C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{FBF43D93-F2E7-4FF8-B4AB-186895949B88}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.SqlServer", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj", "{4BD76717-3102-4969-8C2C-BAAA3F0263B6}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41139F64-4046-4F16-96B7-D941D96FA9C6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" @@ -90,10 +68,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Servic EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServiceBus", "src\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.AzureStorage", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj", "{768C887F-C229-4B94-ACD8-0C7F65686524}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "test\Services\LoadTest\LoadTest.csproj", "{969E793C-C413-490E-9C9D-B2B46DA5AF32}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815B651-941C-466B-AE33-D1D7EEB8F77F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}" @@ -130,7 +104,47 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.UnitTests", "src\Services\Basket\Basket.UnitTests\Basket.UnitTests.csproj", "{9D9CE4E4-1DD0-4961-861F-219731DE06CE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.UnitTests", "src\Services\Catalog\Catalog.UnitTests\Catalog.UnitTests.csproj", "{791961C7-3F3E-434E-B2BA-B4D6B5E222B0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.FunctionalTests", "src\Services\Basket\Basket.FunctionalTests\Basket.FunctionalTests.csproj", "{3F6202D0-2842-4C2F-98E1-9462709EAFBE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.UnitTests", "src\Services\Ordering\Ordering.UnitTests\Ordering.UnitTests.csproj", "{B1182FD9-C245-4018-8412-C66F290C7F4C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.FunctionalTests", "src\Services\Catalog\Catalog.FunctionalTests\Catalog.FunctionalTests.csproj", "{38107691-A437-461D-A85C-ACD3AC7ACFAB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.FunctionalTests", "src\Services\Location\Locations.FunctionalTests\Locations.FunctionalTests.csproj", "{16F463AA-9CF6-44DC-B18C-7310CCF663FF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.FunctionalTests", "src\Services\Ordering\Ordering.FunctionalTests\Ordering.FunctionalTests.csproj", "{DA7D3E03-D0B6-4591-8143-779D3E9F3F30}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.FunctionalTests", "src\Services\Marketing\Marketing.FunctionalTests\Marketing.FunctionalTests.csproj", "{94176D9B-9CAA-4762-8D12-1621E240EE34}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "test\ServicesTests\LoadTest\LoadTest.csproj", "{969E793C-C413-490E-9C9D-B2B46DA5AF32}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.FunctionalTests", "test\ServicesTests\Application.FunctionalTests\Application.FunctionalTests.csproj", "{639BB197-D112-47A7-A44A-471DDB0FA1AE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2751AC5C-D148-4D7A-AE8F-149B47C9A82D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{5FB21302-3973-4992-962A-6F87F5EC99FD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C3F6ED48-E26D-4D57-970F-B82E69467BA1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{32EE4736-7534-47EC-BAAD-C00AF3130F80}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{120CABB3-0FEA-4B40-B4B5-2D3041798C80}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{C61C5CFE-4876-4A46-A96E-5BBF596A984A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Webhooks", "Webhooks", "{E0AA11C4-2873-461D-8F82-53392530FB7A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webhooks.API", "src\Services\Webhooks\Webhooks.API\Webhooks.API.csproj", "{84E2016E-0435-44C6-8020-3D288AA38B2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebhookClient", "src\Web\WebhookClient\WebhookClient.csproj", "{766D7E92-6AF0-476C-ADD5-282BF4D8C576}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -386,54 +400,6 @@ Global {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x64.Build.0 = Release|Any CPU {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x86.ActiveCfg = Release|Any CPU {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x86.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.Build.0 = Release|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -530,102 +496,6 @@ Global {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x64.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.ActiveCfg = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|Any CPU.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|ARM.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|ARM.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhone.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhone.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x64.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x64.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x86.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x86.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|Any CPU.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|ARM.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|ARM.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhone.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhone.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x64.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x64.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x86.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x86.Build.0 = Release|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -770,54 +640,6 @@ Global {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x64.Build.0 = Release|Any CPU {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.ActiveCfg = Release|Any CPU {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.Build.0 = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -866,198 +688,6 @@ Global {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|ARM.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhone.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x64.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x64.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x86.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x86.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|ARM.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|ARM.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhone.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x64.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x64.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x86.ActiveCfg = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x86.Build.0 = Debug|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|Any CPU.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|ARM.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|ARM.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhone.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhone.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.Build.0 = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.ActiveCfg = Release|Any CPU - {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.Build.0 = Release|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1202,102 +832,6 @@ Global {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x64.Build.0 = Release|Any CPU {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.ActiveCfg = Release|Any CPU {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.Build.0 = Release|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1586,6 +1120,630 @@ Global {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x64.Build.0 = Release|Any CPU {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x86.ActiveCfg = Release|Any CPU {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x86.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|ARM.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|iPhone.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|x64.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|x64.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|x86.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.AppStore|x86.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|ARM.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|iPhone.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|x64.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Debug|x86.Build.0 = Debug|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|Any CPU.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|ARM.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|ARM.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|iPhone.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|iPhone.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|x64.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|x64.Build.0 = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|x86.ActiveCfg = Release|Any CPU + {9D9CE4E4-1DD0-4961-861F-219731DE06CE}.Release|x86.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|ARM.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|iPhone.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|x64.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|x64.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|x86.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.AppStore|x86.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|ARM.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|iPhone.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|x64.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|x64.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|x86.ActiveCfg = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Debug|x86.Build.0 = Debug|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|Any CPU.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|ARM.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|ARM.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|iPhone.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|iPhone.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|x64.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|x64.Build.0 = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|x86.ActiveCfg = Release|Any CPU + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0}.Release|x86.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|ARM.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|iPhone.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|x64.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|x64.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|x86.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.AppStore|x86.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|ARM.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|iPhone.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|x64.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|x64.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|x86.ActiveCfg = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Debug|x86.Build.0 = Debug|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|Any CPU.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|ARM.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|ARM.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|iPhone.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|iPhone.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|x64.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|x64.Build.0 = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|x86.ActiveCfg = Release|Any CPU + {3F6202D0-2842-4C2F-98E1-9462709EAFBE}.Release|x86.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|ARM.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|iPhone.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|x64.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|x64.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.AppStore|x86.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|ARM.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|iPhone.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|x64.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|x64.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|x86.ActiveCfg = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Debug|x86.Build.0 = Debug|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|Any CPU.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|ARM.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|ARM.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|iPhone.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|iPhone.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|x64.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|x64.Build.0 = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|x86.ActiveCfg = Release|Any CPU + {B1182FD9-C245-4018-8412-C66F290C7F4C}.Release|x86.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|ARM.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|iPhone.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|x64.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|x64.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|x86.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.AppStore|x86.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|ARM.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|ARM.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|iPhone.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|x64.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|x64.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|x86.ActiveCfg = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Debug|x86.Build.0 = Debug|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|Any CPU.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|ARM.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|ARM.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|iPhone.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|iPhone.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|x64.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|x64.Build.0 = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|x86.ActiveCfg = Release|Any CPU + {38107691-A437-461D-A85C-ACD3AC7ACFAB}.Release|x86.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|ARM.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|iPhone.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|x64.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|x64.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|x86.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.AppStore|x86.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|ARM.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|ARM.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|iPhone.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|x64.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|x64.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|x86.ActiveCfg = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Debug|x86.Build.0 = Debug|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|Any CPU.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|ARM.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|ARM.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|iPhone.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|iPhone.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|x64.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|x64.Build.0 = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|x86.ActiveCfg = Release|Any CPU + {16F463AA-9CF6-44DC-B18C-7310CCF663FF}.Release|x86.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|ARM.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|iPhone.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|x64.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|x64.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|x86.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.AppStore|x86.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|ARM.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|ARM.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|iPhone.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|x64.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|x86.ActiveCfg = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Debug|x86.Build.0 = Debug|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|Any CPU.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|ARM.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|ARM.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|iPhone.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|iPhone.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|x64.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|x64.Build.0 = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|x86.ActiveCfg = Release|Any CPU + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30}.Release|x86.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|ARM.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|iPhone.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|x64.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|x64.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|x86.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.AppStore|x86.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|ARM.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|ARM.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|iPhone.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|x64.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|x64.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|x86.ActiveCfg = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Debug|x86.Build.0 = Debug|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|Any CPU.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|ARM.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|ARM.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|iPhone.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|iPhone.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x64.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x64.Build.0 = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x86.ActiveCfg = Release|Any CPU + {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|ARM.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|iPhone.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|x64.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|x64.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|x86.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.AppStore|x86.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|ARM.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|iPhone.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|x64.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|x64.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|x86.ActiveCfg = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Debug|x86.Build.0 = Debug|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|Any CPU.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|ARM.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|ARM.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|iPhone.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|iPhone.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|x64.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|x64.Build.0 = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|x86.ActiveCfg = Release|Any CPU + {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Release|x86.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|ARM.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|iPhone.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|x64.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|x64.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|x86.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.AppStore|x86.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|ARM.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|iPhone.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|x64.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|x64.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|x86.ActiveCfg = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Debug|x86.Build.0 = Debug|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|Any CPU.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|ARM.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|ARM.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|iPhone.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|iPhone.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|x64.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|x64.Build.0 = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|x86.ActiveCfg = Release|Any CPU + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}.Release|x86.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|ARM.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|iPhone.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|x64.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|x64.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.AppStore|x86.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|ARM.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|iPhone.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|x64.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|x64.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Debug|x86.Build.0 = Debug|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|Any CPU.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|ARM.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|ARM.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|iPhone.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|iPhone.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|x64.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|x64.Build.0 = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|x86.ActiveCfg = Release|Any CPU + {84E2016E-0435-44C6-8020-3D288AA38B2C}.Release|x86.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|ARM.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|iPhone.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|x64.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|x64.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|x86.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.AppStore|x86.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|Any CPU.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|ARM.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|ARM.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|iPhone.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|x64.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|x64.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|x86.ActiveCfg = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Debug|x86.Build.0 = Debug|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|Any CPU.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|Any CPU.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|ARM.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|ARM.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|iPhone.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|iPhone.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x64.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x64.Build.0 = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x86.ActiveCfg = Release|Any CPU + {766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1604,32 +1762,19 @@ Global {F5598DCB-6DDE-4661-AD9D-A55612DA7E76} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} {95F1F07C-4D92-4742-BD07-E5B805AAB651} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} - {7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {A579E108-5445-403D-A407-339AC4D1611B} = {24CD3B53-141E-4A07-9B0D-796641E1CF78} {F16E3C6A-1C94-4EAB-BE91-099618060B68} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} - {5B810E3D-112E-4857-B197-F09D2FD41E27} = {EF0337F2-ED00-4643-89FD-EE10863F1870} - {CFE2FACB-4538-4B99-8A10-306F3882952D} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {DB0EFB20-B024-4E5E-A75C-52143C131D25} = {932D8224-11F6-4D07-B109-DA28AD288A63} {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {0044B293-1DCC-4224-B948-00CF6DC7F510} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} {8088F3FC-6787-45FA-A924-816EC81CBFAC} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} {9EE28E45-1533-472B-8267-56C48855BA0E} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} - {A81ECBC2-6B00-4DCD-8388-469174033379} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} - {942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379} {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} - {FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88} - {022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} - {1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5} - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379} - {4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379} {41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6} {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} - {768C887F-C229-4B94-ACD8-0C7F65686524} = {A81ECBC2-6B00-4DCD-8388-469174033379} - {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F} {77849D35-37D4-4802-81DC-9477B2775A40} = {932D8224-11F6-4D07-B109-DA28AD288A63} @@ -1643,6 +1788,26 @@ Global {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F} {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {E1D2B260-4E7F-4A88-BC13-9910F7C44623} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} + {9D9CE4E4-1DD0-4961-861F-219731DE06CE} = {2751AC5C-D148-4D7A-AE8F-149B47C9A82D} + {791961C7-3F3E-434E-B2BA-B4D6B5E222B0} = {5FB21302-3973-4992-962A-6F87F5EC99FD} + {3F6202D0-2842-4C2F-98E1-9462709EAFBE} = {2751AC5C-D148-4D7A-AE8F-149B47C9A82D} + {B1182FD9-C245-4018-8412-C66F290C7F4C} = {120CABB3-0FEA-4B40-B4B5-2D3041798C80} + {38107691-A437-461D-A85C-ACD3AC7ACFAB} = {5FB21302-3973-4992-962A-6F87F5EC99FD} + {16F463AA-9CF6-44DC-B18C-7310CCF663FF} = {C3F6ED48-E26D-4D57-970F-B82E69467BA1} + {DA7D3E03-D0B6-4591-8143-779D3E9F3F30} = {120CABB3-0FEA-4B40-B4B5-2D3041798C80} + {94176D9B-9CAA-4762-8D12-1621E240EE34} = {32EE4736-7534-47EC-BAAD-C00AF3130F80} + {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} + {639BB197-D112-47A7-A44A-471DDB0FA1AE} = {EF0337F2-ED00-4643-89FD-EE10863F1870} + {2751AC5C-D148-4D7A-AE8F-149B47C9A82D} = {BF3EF4F3-E4F5-41DA-9D2D-57223687D1A8} + {5FB21302-3973-4992-962A-6F87F5EC99FD} = {326A7FB3-5295-468C-A4FE-67DCB823E1E5} + {C3F6ED48-E26D-4D57-970F-B82E69467BA1} = {41139F64-4046-4F16-96B7-D941D96FA9C6} + {32EE4736-7534-47EC-BAAD-C00AF3130F80} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} + {120CABB3-0FEA-4B40-B4B5-2D3041798C80} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} + {C61C5CFE-4876-4A46-A96E-5BBF596A984A} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} + {0AB40131-8AD7-436F-9C6B-EDA59CFA3A84} = {C61C5CFE-4876-4A46-A96E-5BBF596A984A} + {E0AA11C4-2873-461D-8F82-53392530FB7A} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} + {84E2016E-0435-44C6-8020-3D288AA38B2C} = {E0AA11C4-2873-461D-8F82-53392530FB7A} + {766D7E92-6AF0-476C-ADD5-282BF4D8C576} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} diff --git a/eShopOnContainers.sln b/eShopOnContainers.sln index ebee1f162..8e08a05fa 100644 --- a/eShopOnContainers.sln +++ b/eShopOnContainers.sln @@ -25,7 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ordering", "Ordering", "{0B EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A857AD10-40FF-4303-BEC2-FF1C58D5735E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{EF0337F2-ED00-4643-89FD-EE10863F1870}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServicesTests", "ServicesTests", "{EF0337F2-ED00-4643-89FD-EE10863F1870}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{24CD3B53-141E-4A07-9B0D-796641E1CF78}" EndProject @@ -41,16 +41,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebMVC", "src\Web\WebMVC\We EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "src\Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\UnitTest\UnitTest.csproj", "{7796F5D8-31FC-45A4-B673-19DE5BA194CF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "test\Services\IntegrationTests\IntegrationTests.csproj", "{5B810E3D-112E-4857-B197-F09D2FD41E27}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "test\Services\FunctionalTests\FunctionalTests.csproj", "{CFE2FACB-4538-4B99-8A10-306F3882952D}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{DB0EFB20-B024-4E5E-A75C-52143C131D25}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}" @@ -61,24 +55,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\Bui EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{A81ECBC2-6B00-4DCD-8388-469174033379}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj", "{942ED6E8-0050-495F-A0EA-01E97F63760C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{FBF43D93-F2E7-4FF8-B4AB-186895949B88}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.SqlServer", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj", "{4BD76717-3102-4969-8C2C-BAAA3F0263B6}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41139F64-4046-4F16-96B7-D941D96FA9C6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" @@ -89,10 +71,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Servic EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServiceBus", "src\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.AzureStorage", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj", "{768C887F-C229-4B94-ACD8-0C7F65686524}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "test\Services\LoadTest\LoadTest.csproj", "{969E793C-C413-490E-9C9D-B2B46DA5AF32}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815B651-941C-466B-AE33-D1D7EEB8F77F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}" @@ -123,6 +101,66 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunne EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.FunctionalTests", "src\Services\Basket\Basket.FunctionalTests\Basket.FunctionalTests.csproj", "{9F00E62F-E180-4A9C-8794-98A72AFAC2DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.UnitTests", "src\Services\Basket\Basket.UnitTests\Basket.UnitTests.csproj", "{63417272-1E6A-406A-AD11-C738558D89C0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.FunctionalTests", "src\Services\Catalog\Catalog.FunctionalTests\Catalog.FunctionalTests.csproj", "{56E0E455-731E-41CB-AF46-C1A70F8A140B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.UnitTests", "src\Services\Catalog\Catalog.UnitTests\Catalog.UnitTests.csproj", "{1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.FunctionalTests", "src\Services\Location\Locations.FunctionalTests\Locations.FunctionalTests.csproj", "{4F0E5CB2-5795-4040-8637-1D395914C944}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.FunctionalTests", "src\Services\Marketing\Marketing.FunctionalTests\Marketing.FunctionalTests.csproj", "{22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.FunctionalTests", "src\Services\Ordering\Ordering.FunctionalTests\Ordering.FunctionalTests.csproj", "{5A155B15-D8E7-47FE-8D17-8E641726158C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.UnitTests", "src\Services\Ordering\Ordering.UnitTests\Ordering.UnitTests.csproj", "{0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "test\ServicesTests\LoadTest\LoadTest.csproj", "{969E793C-C413-490E-9C9D-B2B46DA5AF32}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.FunctionalTests", "test\ServicesTests\Application.FunctionalTests\Application.FunctionalTests.csproj", "{3572B4E2-4399-4797-B5C2-3720D870E0C3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7BA332A2-189D-4D03-9935-FDFF81C42496}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2F0DEF71-84AC-4212-86D4-E36E8896BDBF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2B26A7AA-6D61-42FA-8AB7-C0F05AAE7F1C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DA1786E4-30AB-434E-A827-92896390B79D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{30308DE0-8128-4613-BCAD-B0BEFFB20E38}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateways", "ApiGateways", "{79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGw-Base", "ApiGw-Base", "{56AD1FCA-6E16-4798-BF29-941C5B3277D2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Marketing", "Mobile.Bff.Marketing", "{34ED3311-2B30-4C8B-823B-312B50FFC32A}" + ProjectSection(SolutionItems) = preProject + src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Shopping", "Mobile.Bff.Shopping", "{A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0}" + ProjectSection(SolutionItems) = preProject + src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Marketing", "Web.Bff.Marketing", "{696D2B7E-6B75-401D-964A-BFE6F4D7AF73}" + ProjectSection(SolutionItems) = preProject + src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Shopping", "Web.Bff.Shopping", "{424BC53E-17EA-4E12-BC07-64BAA927ABCB}" + ProjectSection(SolutionItems) = preProject + src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApiGw", "src\ApiGateways\ApiGw-Base\OcelotApiGw.csproj", "{0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "src\ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj", "{98E0B3BA-6601-4C59-A9AA-24A00A17D835}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{E39BD762-BC86-459D-B818-B6BF2D9F1352}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -377,54 +415,6 @@ Global {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x64.Build.0 = Release|Any CPU {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x86.ActiveCfg = Release|Any CPU {95F1F07C-4D92-4742-BD07-E5B805AAB651}.Release|x86.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.ActiveCfg = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.Build.0 = Debug|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.Build.0 = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.ActiveCfg = Release|Any CPU - {7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.Build.0 = Release|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -521,102 +511,6 @@ Global {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x64.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.ActiveCfg = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.AppStore|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|ARM.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|ARM.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhone.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x64.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x64.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x86.ActiveCfg = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Debug|x86.Build.0 = Debug|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|Any CPU.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|ARM.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|ARM.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhone.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhone.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x64.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x64.Build.0 = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x86.ActiveCfg = Release|Any CPU - {5B810E3D-112E-4857-B197-F09D2FD41E27}.Release|x86.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.AppStore|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|ARM.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|ARM.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhone.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x64.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x64.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x86.ActiveCfg = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Debug|x86.Build.0 = Debug|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|Any CPU.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|ARM.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|ARM.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhone.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhone.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x64.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x64.Build.0 = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x86.ActiveCfg = Release|Any CPU - {CFE2FACB-4538-4B99-8A10-306F3882952D}.Release|x86.Build.0 = Release|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {0044B293-1DCC-4224-B948-00CF6DC7F510}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -761,54 +655,6 @@ Global {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x64.Build.0 = Release|Any CPU {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.ActiveCfg = Release|Any CPU {9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.ActiveCfg = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.Build.0 = Debug|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.Build.0 = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.ActiveCfg = Release|Any CPU - {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.Build.0 = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -857,54 +703,6 @@ Global {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.ActiveCfg = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.Build.0 = Debug|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -953,102 +751,6 @@ Global {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.Build.0 = Release|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.ActiveCfg = Release|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.ActiveCfg = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.Build.0 = Debug|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.Build.0 = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.ActiveCfg = Release|Any CPU - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.ActiveCfg = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.Build.0 = Debug|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.Build.0 = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.ActiveCfg = Release|Any CPU - {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.Build.0 = Release|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1193,102 +895,6 @@ Global {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x64.Build.0 = Release|Any CPU {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.ActiveCfg = Release|Any CPU {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.ActiveCfg = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.Build.0 = Debug|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.Build.0 = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.ActiveCfg = Release|Any CPU - {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.Build.0 = Release|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1809,6 +1415,630 @@ Global {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x64.Build.0 = Release|Any CPU {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x86.ActiveCfg = Release|Any CPU {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x86.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|ARM.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|iPhone.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|x64.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|x64.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|x86.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.AppStore|x86.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|ARM.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|iPhone.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|x64.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Debug|x86.Build.0 = Debug|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|Any CPU.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|ARM.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|ARM.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|iPhone.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|iPhone.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|x64.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|x64.Build.0 = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|x86.ActiveCfg = Release|Any CPU + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Release|x86.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|ARM.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|iPhone.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|x64.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|x64.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|x86.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.AppStore|x86.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|ARM.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|iPhone.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|x64.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|x64.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|x86.ActiveCfg = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Debug|x86.Build.0 = Debug|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|Any CPU.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|ARM.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|ARM.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|iPhone.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|iPhone.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|x64.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|x64.Build.0 = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|x86.ActiveCfg = Release|Any CPU + {63417272-1E6A-406A-AD11-C738558D89C0}.Release|x86.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|ARM.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|iPhone.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|x64.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|x64.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|x86.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.AppStore|x86.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|ARM.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|iPhone.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|x64.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|x64.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|x86.ActiveCfg = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Debug|x86.Build.0 = Debug|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|Any CPU.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|ARM.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|ARM.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|iPhone.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|iPhone.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|x64.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|x64.Build.0 = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|x86.ActiveCfg = Release|Any CPU + {56E0E455-731E-41CB-AF46-C1A70F8A140B}.Release|x86.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|ARM.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|iPhone.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|x64.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|x64.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|x86.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.AppStore|x86.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|ARM.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|ARM.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|iPhone.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|x64.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|x64.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|x86.ActiveCfg = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Debug|x86.Build.0 = Debug|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|Any CPU.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|ARM.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|ARM.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|iPhone.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|iPhone.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|x64.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|x64.Build.0 = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|x86.ActiveCfg = Release|Any CPU + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5}.Release|x86.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|ARM.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|iPhone.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|x64.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|x64.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|x86.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.AppStore|x86.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|ARM.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|ARM.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|iPhone.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|x64.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|x64.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Debug|x86.Build.0 = Debug|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|Any CPU.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|ARM.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|ARM.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|iPhone.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|iPhone.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|x64.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|x64.Build.0 = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|x86.ActiveCfg = Release|Any CPU + {4F0E5CB2-5795-4040-8637-1D395914C944}.Release|x86.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|ARM.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|iPhone.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|x64.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|x64.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|x86.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.AppStore|x86.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|ARM.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|iPhone.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|x64.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|x64.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|x86.ActiveCfg = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Debug|x86.Build.0 = Debug|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|Any CPU.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|ARM.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|ARM.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|iPhone.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|iPhone.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|x64.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|x64.Build.0 = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|x86.ActiveCfg = Release|Any CPU + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8}.Release|x86.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|ARM.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|iPhone.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|x64.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|x64.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.AppStore|x86.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|ARM.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|iPhone.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|x64.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|x64.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|x86.ActiveCfg = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Debug|x86.Build.0 = Debug|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|Any CPU.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|ARM.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|ARM.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|iPhone.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|iPhone.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|x64.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|x64.Build.0 = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|x86.ActiveCfg = Release|Any CPU + {5A155B15-D8E7-47FE-8D17-8E641726158C}.Release|x86.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|ARM.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|iPhone.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|x64.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|x64.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|x86.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.AppStore|x86.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|ARM.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|iPhone.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|x64.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|x86.ActiveCfg = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Debug|x86.Build.0 = Debug|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|Any CPU.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|ARM.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|ARM.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|iPhone.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|iPhone.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|x64.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|x64.Build.0 = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|x86.ActiveCfg = Release|Any CPU + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A}.Release|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.ActiveCfg = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.Build.0 = Debug|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.Build.0 = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.ActiveCfg = Release|Any CPU + {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|ARM.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|iPhone.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|x64.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|x64.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|x86.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.AppStore|x86.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|ARM.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|iPhone.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|x64.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|x64.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|x86.ActiveCfg = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Debug|x86.Build.0 = Debug|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|Any CPU.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|ARM.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|ARM.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|iPhone.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|iPhone.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x64.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x64.Build.0 = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x86.ActiveCfg = Release|Any CPU + {3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x86.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|ARM.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhone.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x64.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x64.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x86.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x86.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|ARM.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhone.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x64.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x86.ActiveCfg = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x86.Build.0 = Debug|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|Any CPU.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|ARM.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|ARM.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhone.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhone.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x64.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x64.Build.0 = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x86.ActiveCfg = Release|Any CPU + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x86.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|ARM.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhone.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x64.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x64.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x86.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x86.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|ARM.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|ARM.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhone.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x64.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x64.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x86.ActiveCfg = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x86.Build.0 = Debug|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|Any CPU.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|ARM.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|ARM.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhone.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhone.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x64.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x64.Build.0 = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x86.ActiveCfg = Release|Any CPU + {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x86.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|ARM.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhone.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x64.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x64.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x86.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x86.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|ARM.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhone.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x64.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x64.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x86.ActiveCfg = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x86.Build.0 = Debug|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|Any CPU.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|ARM.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|ARM.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhone.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhone.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x64.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x64.Build.0 = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x86.ActiveCfg = Release|Any CPU + {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1827,32 +2057,21 @@ Global {F5598DCB-6DDE-4661-AD9D-A55612DA7E76} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} {95F1F07C-4D92-4742-BD07-E5B805AAB651} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} - {7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {A579E108-5445-403D-A407-339AC4D1611B} = {24CD3B53-141E-4A07-9B0D-796641E1CF78} {F16E3C6A-1C94-4EAB-BE91-099618060B68} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} - {5B810E3D-112E-4857-B197-F09D2FD41E27} = {EF0337F2-ED00-4643-89FD-EE10863F1870} - {CFE2FACB-4538-4B99-8A10-306F3882952D} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {DB0EFB20-B024-4E5E-A75C-52143C131D25} = {932D8224-11F6-4D07-B109-DA28AD288A63} {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {0044B293-1DCC-4224-B948-00CF6DC7F510} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} {8088F3FC-6787-45FA-A924-816EC81CBFAC} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} {9EE28E45-1533-472B-8267-56C48855BA0E} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} - {A81ECBC2-6B00-4DCD-8388-469174033379} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} - {942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379} {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} - {FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} - {D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88} {022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5} - {22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379} - {4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379} {41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6} {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} {69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} - {768C887F-C229-4B94-ACD8-0C7F65686524} = {A81ECBC2-6B00-4DCD-8388-469174033379} - {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F} {EF3EDC78-E864-43FF-8E80-CF33DD9508A3} = {932D8224-11F6-4D07-B109-DA28AD288A63} @@ -1868,6 +2087,30 @@ Global {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3} = {0AAED9FF-3260-43BB-B586-9AAF1E010A90} {A7337243-33B8-463A-87AD-944B75EFD820} = {0AAED9FF-3260-43BB-B586-9AAF1E010A90} {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} + {9F00E62F-E180-4A9C-8794-98A72AFAC2DB} = {7BA332A2-189D-4D03-9935-FDFF81C42496} + {63417272-1E6A-406A-AD11-C738558D89C0} = {7BA332A2-189D-4D03-9935-FDFF81C42496} + {56E0E455-731E-41CB-AF46-C1A70F8A140B} = {2F0DEF71-84AC-4212-86D4-E36E8896BDBF} + {1EB6680D-4AC8-47EF-A026-E4EEEE93CAD5} = {2F0DEF71-84AC-4212-86D4-E36E8896BDBF} + {4F0E5CB2-5795-4040-8637-1D395914C944} = {2B26A7AA-6D61-42FA-8AB7-C0F05AAE7F1C} + {22F59DDE-D0BC-4D58-BCDE-240C7EEBECB8} = {DA1786E4-30AB-434E-A827-92896390B79D} + {5A155B15-D8E7-47FE-8D17-8E641726158C} = {30308DE0-8128-4613-BCAD-B0BEFFB20E38} + {0A9643F2-FF99-4DA0-BC2B-D62D5D3C317A} = {30308DE0-8128-4613-BCAD-B0BEFFB20E38} + {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} + {3572B4E2-4399-4797-B5C2-3720D870E0C3} = {EF0337F2-ED00-4643-89FD-EE10863F1870} + {7BA332A2-189D-4D03-9935-FDFF81C42496} = {BF3EF4F3-E4F5-41DA-9D2D-57223687D1A8} + {2F0DEF71-84AC-4212-86D4-E36E8896BDBF} = {326A7FB3-5295-468C-A4FE-67DCB823E1E5} + {2B26A7AA-6D61-42FA-8AB7-C0F05AAE7F1C} = {41139F64-4046-4F16-96B7-D941D96FA9C6} + {DA1786E4-30AB-434E-A827-92896390B79D} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} + {30308DE0-8128-4613-BCAD-B0BEFFB20E38} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} + {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} = {932D8224-11F6-4D07-B109-DA28AD288A63} + {56AD1FCA-6E16-4798-BF29-941C5B3277D2} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} + {34ED3311-2B30-4C8B-823B-312B50FFC32A} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} + {A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} + {696D2B7E-6B75-401D-964A-BFE6F4D7AF73} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} + {424BC53E-17EA-4E12-BC07-64BAA927ABCB} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} + {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC} = {56AD1FCA-6E16-4798-BF29-941C5B3277D2} + {98E0B3BA-6601-4C59-A9AA-24A00A17D835} = {A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0} + {E39BD762-BC86-459D-B818-B6BF2D9F1352} = {424BC53E-17EA-4E12-BC07-64BAA927ABCB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} diff --git a/global.json b/global.json deleted file mode 100644 index 00b3f36f2..000000000 --- a/global.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sdk": { - "version": "2.1.4" - } -} \ No newline at end of file diff --git a/hosts b/hosts deleted file mode 100644 index 19e812a15..000000000 --- a/hosts +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 1993-2009 Microsoft Corp. -# -# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. -# -# This file contains the mappings of IP addresses to host names. Each -# entry should be kept on an individual line. The IP address should -# be placed in the first column followed by the corresponding host name. -# The IP address and the host name should be separated by at least one -# space. -# -# Additionally, comments (such as these) may be inserted on individual -# lines or following the machine name denoted by a '#' symbol. -# -# For example: -# -# 102.54.94.97 rhino.acme.com # source server -# 38.25.63.10 x.acme.com # x client host - -# localhost name resolution is handled within DNS itself. -# 127.0.0.1 localhost -# ::1 localhost - - 10.0.75.1 identity.service \ No newline at end of file diff --git a/k8s/deploy-ingress-azure.ps1 b/k8s/deploy-ingress-azure.ps1 index f93cf437b..d0ff702df 100644 --- a/k8s/deploy-ingress-azure.ps1 +++ b/k8s/deploy-ingress-azure.ps1 @@ -1,3 +1 @@ -kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type=json --patch="$(cat nginx-ingress\publish-service-patch.yaml)" -kubectl apply -f nginx-ingress\azure\service.yaml -kubectl apply -f nginx-ingress\patch-service-without-rbac.yaml \ No newline at end of file +kubectl apply -f nginx-ingress\cloud-generic.yaml \ No newline at end of file diff --git a/k8s/deploy-ingress-dockerlocal.ps1 b/k8s/deploy-ingress-dockerlocal.ps1 new file mode 100644 index 000000000..04ffad763 --- /dev/null +++ b/k8s/deploy-ingress-dockerlocal.ps1 @@ -0,0 +1,2 @@ +kubectl apply -f nginx-ingress\cm.yaml +kubectl apply -f nginx-ingress\cloud-generic.yaml \ No newline at end of file diff --git a/k8s/deploy-ingress.ps1 b/k8s/deploy-ingress.ps1 index 694361bfa..37abcbee2 100644 --- a/k8s/deploy-ingress.ps1 +++ b/k8s/deploy-ingress.ps1 @@ -1,12 +1,5 @@ -kubectl apply -f ingress.yaml - # Deploy nginx-ingress core files -kubectl apply -f nginx-ingress\namespace.yaml -kubectl apply -f nginx-ingress\default-backend.yaml -kubectl apply -f nginx-ingress\configmap.yaml -kubectl apply -f nginx-ingress\tcp-services-configmap.yaml -kubectl apply -f nginx-ingress\udp-services-configmap.yaml -kubectl apply -f nginx-ingress\without-rbac.yaml +kubectl apply -f nginx-ingress\mandatory.yaml diff --git a/k8s/deploy.ps1 b/k8s/deploy.ps1 index f0905096a..abeb12aed 100644 --- a/k8s/deploy.ps1 +++ b/k8s/deploy.ps1 @@ -113,6 +113,7 @@ ExecKube -cmd 'delete configmap internalurls' ExecKube -cmd 'delete configmap urls' ExecKube -cmd 'delete configmap externalcfg' ExecKube -cmd 'delete configmap ocelot' +ExecKube -cmd 'delete -f ingress.yaml' # start sql, rabbitmq, frontend deployments if ($deployInfrastructure) { @@ -204,5 +205,8 @@ ExecKube -cmd 'rollout resume deployments/apigwwm' ExecKube -cmd 'rollout resume deployments/apigwws' ExecKube -cmd 'rollout resume deployments/ordering-signalrhub' +Write-Host "Adding/Updating ingress resource..." -ForegroundColor Yellow +ExecKube -cmd 'apply -f ingress.yaml' + Write-Host "WebSPA is exposed at http://$externalDns, WebMVC at http://$externalDns/webmvc, WebStatus at http://$externalDns/webstatus" -ForegroundColor Yellow diff --git a/k8s/helm-rbac.yaml b/k8s/helm-rbac.yaml new file mode 100644 index 000000000..b6180329a --- /dev/null +++ b/k8s/helm-rbac.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tiller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: tiller + namespace: kube-system \ No newline at end of file diff --git a/k8s/helm/aks-httpaddon-cfg.yaml b/k8s/helm/aks-httpaddon-cfg.yaml new file mode 100644 index 000000000..b9576b0b6 --- /dev/null +++ b/k8s/helm/aks-httpaddon-cfg.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: +# addonmanager.kubernetes.io/mode: Reconcile + app: addon-http-application-routing-ingress-nginx + kubernetes.io/cluster-service: "true" + name: addon-http-application-routing-nginx-configuration + namespace: kube-system +data: + proxy-buffer-size: "128k" + proxy-buffers: "4 256k" diff --git a/k8s/helm/apigwmm/.helmignore b/k8s/helm/apigwmm/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/apigwmm/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/apigwmm/Chart.yaml b/k8s/helm/apigwmm/Chart.yaml new file mode 100644 index 000000000..50b3d07c6 --- /dev/null +++ b/k8s/helm/apigwmm/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: apigwmm +version: 0.1.0 diff --git a/k8s/helm/apigwmm/configuration-mobile-marketing.json b/k8s/helm/apigwmm/configuration-mobile-marketing.json new file mode 100644 index 000000000..666df1633 --- /dev/null +++ b/k8s/helm/apigwmm/configuration-mobile-marketing.json @@ -0,0 +1,34 @@ +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "marketing", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/m/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "locations", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/l/{everything}", + "UpstreamHttpMethod": [] + } + + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration" + } +} + \ No newline at end of file diff --git a/k8s/helm/apigwmm/templates/NOTES.txt b/k8s/helm/apigwmm/templates/NOTES.txt new file mode 100644 index 000000000..30ef33447 --- /dev/null +++ b/k8s/helm/apigwmm/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop API Gateway for Mobile Marketing services installed +---------------------------------------------------------- \ No newline at end of file diff --git a/k8s/helm/apigwmm/templates/_helpers.tpl b/k8s/helm/apigwmm/templates/_helpers.tpl new file mode 100644 index 000000000..fd3d89212 --- /dev/null +++ b/k8s/helm/apigwmm/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "apigwmm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "apigwmm.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "apigwmm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/apigwmm/templates/_names.tpl b/k8s/helm/apigwmm/templates/_names.tpl new file mode 100644 index 000000000..a6eeb9965 --- /dev/null +++ b/k8s/helm/apigwmm/templates/_names.tpl @@ -0,0 +1,53 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if $ctx.Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" $ctx -}} +{{- printf "/%s-%s" $name $suffix -}} +{{- else -}} +{{- printf "/%s" $name -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/apigwmm/templates/configmap.yaml b/k8s/helm/apigwmm/templates/configmap.yaml new file mode 100644 index 000000000..fbffcd339 --- /dev/null +++ b/k8s/helm/apigwmm/templates/configmap.yaml @@ -0,0 +1,21 @@ +{{- $name := include "apigwmm.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "apigwmm.name" . }} + chart: {{ template "apigwmm.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + diff --git a/k8s/helm/apigwmm/templates/deployment.yaml b/k8s/helm/apigwmm/templates/deployment.yaml new file mode 100644 index 000000000..6dc58bf50 --- /dev/null +++ b/k8s/helm/apigwmm/templates/deployment.yaml @@ -0,0 +1,103 @@ +{{- $name := include "apigwmm.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "apigwmm.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "apigwmm.name" . }} + chart: {{ template "apigwmm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "apigwmm.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "apigwmm.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ $ocelotcfgname }} + items: + - key: configuration-mobile-marketing.json + path: configuration.json + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: config + mountPath: /app/configuration + env: + - name: PATH_BASE + value: {{ include "pathBase" (list .Values.app.ingress.entries.mobilemarketingapigw .) }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/apigwmm/templates/ingress.yaml b/k8s/helm/apigwmm/templates/ingress.yaml new file mode 100644 index 000000000..28e2aa84d --- /dev/null +++ b/k8s/helm/apigwmm/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.mobilemarketingapigw .) -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "apigwmm.fullname" . }} + labels: + app: {{ template "apigwmm.name" . }} + chart: {{ template "apigwmm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.mobilemarketingapigw }} + servicePort: http +{{- end }} diff --git a/k8s/helm/apigwmm/templates/ocelot-cm.yaml b/k8s/helm/apigwmm/templates/ocelot-cm.yaml new file mode 100644 index 000000000..c7c20ce06 --- /dev/null +++ b/k8s/helm/apigwmm/templates/ocelot-cm.yaml @@ -0,0 +1,14 @@ +{{- $name := include "apigwmm.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "ocelot-{{ $name }}" + labels: + app: {{ template "apigwmm.name" . }} + chart: {{ template "apigwmm.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + {{ (.Files.Glob "configuration-mobile-marketing.json").AsConfig | indent 2 }} + diff --git a/k8s/helm/apigwmm/templates/service.yaml b/k8s/helm/apigwmm/templates/service.yaml new file mode 100644 index 000000000..dac59b23a --- /dev/null +++ b/k8s/helm/apigwmm/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.mobilemarketingapigw }} + labels: + app: {{ template "apigwmm.name" . }} + chart: {{ template "apigwmm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "apigwmm.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/apigwmm/values.yaml b/k8s/helm/apigwmm/values.yaml new file mode 100644 index 000000000..501266780 --- /dev/null +++ b/k8s/helm/apigwmm/values.yaml @@ -0,0 +1,64 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /mobilemarketingapigw + +image: + repository: eshop/ocelotapigw + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: IdentityUrl + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/apigwms/.helmignore b/k8s/helm/apigwms/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/apigwms/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/apigwms/Chart.yaml b/k8s/helm/apigwms/Chart.yaml new file mode 100644 index 000000000..3ad3fdf46 --- /dev/null +++ b/k8s/helm/apigwms/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: apigwms +version: 0.1.0 diff --git a/k8s/helm/apigwms/configuration-mobile-shopping.json b/k8s/helm/apigwms/configuration-mobile-shopping.json new file mode 100644 index 000000000..cf3a48aff --- /dev/null +++ b/k8s/helm/apigwms/configuration-mobile-shopping.json @@ -0,0 +1,142 @@ +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "catalog", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/c/{everything}", + "UpstreamHttpMethod": [ "GET" ] + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/b/{everything}", + "UpstreamHttpMethod": [], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "ordering", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/o/{everything}", + "UpstreamHttpMethod": [], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "mobileshoppingagg", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/{everything}", + "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "ordering", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/orders-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/basket-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "catalog", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/catalog-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "marketing", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/marketing-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "payment", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/payment-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "locations.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/location-api/{everything}", + "UpstreamHttpMethod": [] + } + + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration" + } + } + \ No newline at end of file diff --git a/k8s/helm/apigwms/templates/NOTES.txt b/k8s/helm/apigwms/templates/NOTES.txt new file mode 100644 index 000000000..74b3eedda --- /dev/null +++ b/k8s/helm/apigwms/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop API Gateway for Mobile Shopping services installed +-------------------------------------------------------- \ No newline at end of file diff --git a/k8s/helm/apigwms/templates/_helpers.tpl b/k8s/helm/apigwms/templates/_helpers.tpl new file mode 100644 index 000000000..2ae403c2f --- /dev/null +++ b/k8s/helm/apigwms/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "apigwms.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "apigwms.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "apigwms.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/apigwms/templates/_names.tpl b/k8s/helm/apigwms/templates/_names.tpl new file mode 100644 index 000000000..1e840c56c --- /dev/null +++ b/k8s/helm/apigwms/templates/_names.tpl @@ -0,0 +1,54 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if $ctx.Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" $ctx -}} +{{- printf "/%s-%s" $name $suffix -}} +{{- else -}} +{{- printf "/%s" $name -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/apigwms/templates/configmap.yaml b/k8s/helm/apigwms/templates/configmap.yaml new file mode 100644 index 000000000..f3292ce72 --- /dev/null +++ b/k8s/helm/apigwms/templates/configmap.yaml @@ -0,0 +1,21 @@ +{{- $name := include "apigwms.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "apigwms.name" . }} + chart: {{ template "apigwms.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + diff --git a/k8s/helm/apigwms/templates/deployment.yaml b/k8s/helm/apigwms/templates/deployment.yaml new file mode 100644 index 000000000..8a4fd8942 --- /dev/null +++ b/k8s/helm/apigwms/templates/deployment.yaml @@ -0,0 +1,103 @@ +{{- $name := include "apigwms.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "apigwms.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "apigwms.name" . }} + chart: {{ template "apigwms.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "apigwms.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "apigwms.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ $ocelotcfgname }} + items: + - key: configuration-mobile-shopping.json + path: configuration.json + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: config + mountPath: /app/configuration + env: + - name: PATH_BASE + value: {{ include "pathBase" (list .Values.app.ingress.entries.mobileshoppingapigw .) }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/apigwms/templates/ingress.yaml b/k8s/helm/apigwms/templates/ingress.yaml new file mode 100644 index 000000000..7dd50d8dd --- /dev/null +++ b/k8s/helm/apigwms/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.mobileshoppingapigw .) -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "apigwms.fullname" . }} + labels: + app: {{ template "apigwms.name" . }} + chart: {{ template "apigwms.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.mobileshoppingapigw }} + servicePort: http +{{- end }} diff --git a/k8s/helm/apigwms/templates/ocelot-cm.yaml b/k8s/helm/apigwms/templates/ocelot-cm.yaml new file mode 100644 index 000000000..5f92ca409 --- /dev/null +++ b/k8s/helm/apigwms/templates/ocelot-cm.yaml @@ -0,0 +1,14 @@ +{{- $name := include "apigwms.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "ocelot-{{ $name }}" + labels: + app: {{ template "apigwms.name" . }} + chart: {{ template "apigwms.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + {{ (.Files.Glob "configuration-mobile-shopping.json").AsConfig | indent 2 }} + diff --git a/k8s/helm/apigwms/templates/service.yaml b/k8s/helm/apigwms/templates/service.yaml new file mode 100644 index 000000000..2a37d3c14 --- /dev/null +++ b/k8s/helm/apigwms/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.mobileshoppingapigw }} + labels: + app: {{ template "apigwms.name" . }} + chart: {{ template "apigwms.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "apigwms.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/apigwms/values.yaml b/k8s/helm/apigwms/values.yaml new file mode 100644 index 000000000..58377ec5b --- /dev/null +++ b/k8s/helm/apigwms/values.yaml @@ -0,0 +1,64 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /mobileshoppingapigw + +image: + repository: eshop/ocelotapigw + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: IdentityUrl + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 \ No newline at end of file diff --git a/k8s/helm/apigwwm/.helmignore b/k8s/helm/apigwwm/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/apigwwm/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/apigwwm/Chart.yaml b/k8s/helm/apigwwm/Chart.yaml new file mode 100644 index 000000000..4c2082969 --- /dev/null +++ b/k8s/helm/apigwwm/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: apigwwm +version: 0.1.0 diff --git a/k8s/helm/apigwwm/configuration-web-marketing.json b/k8s/helm/apigwwm/configuration-web-marketing.json new file mode 100644 index 000000000..666df1633 --- /dev/null +++ b/k8s/helm/apigwwm/configuration-web-marketing.json @@ -0,0 +1,34 @@ +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "marketing", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/m/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "locations", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/l/{everything}", + "UpstreamHttpMethod": [] + } + + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration" + } +} + \ No newline at end of file diff --git a/k8s/helm/apigwwm/templates/NOTES.txt b/k8s/helm/apigwwm/templates/NOTES.txt new file mode 100644 index 000000000..3420c97c8 --- /dev/null +++ b/k8s/helm/apigwwm/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop API Gateway for Web Marketing services installed +------------------------------------------------------ \ No newline at end of file diff --git a/k8s/helm/apigwwm/templates/_helpers.tpl b/k8s/helm/apigwwm/templates/_helpers.tpl new file mode 100644 index 000000000..194cf96ca --- /dev/null +++ b/k8s/helm/apigwwm/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "apigwwm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "apigwwm.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "apigwwm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/apigwwm/templates/_names.tpl b/k8s/helm/apigwwm/templates/_names.tpl new file mode 100644 index 000000000..1e840c56c --- /dev/null +++ b/k8s/helm/apigwwm/templates/_names.tpl @@ -0,0 +1,54 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if $ctx.Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" $ctx -}} +{{- printf "/%s-%s" $name $suffix -}} +{{- else -}} +{{- printf "/%s" $name -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/apigwwm/templates/configmap.yaml b/k8s/helm/apigwwm/templates/configmap.yaml new file mode 100644 index 000000000..34c0e6979 --- /dev/null +++ b/k8s/helm/apigwwm/templates/configmap.yaml @@ -0,0 +1,21 @@ +{{- $name := include "apigwwm.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "apigwwm.name" . }} + chart: {{ template "apigwwm.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + diff --git a/k8s/helm/apigwwm/templates/deployment.yaml b/k8s/helm/apigwwm/templates/deployment.yaml new file mode 100644 index 000000000..5cbce9f22 --- /dev/null +++ b/k8s/helm/apigwwm/templates/deployment.yaml @@ -0,0 +1,103 @@ +{{- $name := include "apigwwm.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "apigwwm.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "apigwwm.name" . }} + chart: {{ template "apigwwm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "apigwwm.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "apigwwm.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ $ocelotcfgname }} + items: + - key: configuration-web-marketing.json + path: configuration.json + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: config + mountPath: /app/configuration + env: + - name: PATH_BASE + value: {{ include "pathBase" (list .Values.app.ingress.entries.webmarketingapigw .) }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/apigwwm/templates/ingress.yaml b/k8s/helm/apigwwm/templates/ingress.yaml new file mode 100644 index 000000000..0a79c4660 --- /dev/null +++ b/k8s/helm/apigwwm/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.webmarketingapigw .) -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "apigwwm.fullname" . }} + labels: + app: {{ template "apigwwm.name" . }} + chart: {{ template "apigwwm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.webmarketingapigw }} + servicePort: http +{{- end }} diff --git a/k8s/helm/apigwwm/templates/ocelot-cm.yaml b/k8s/helm/apigwwm/templates/ocelot-cm.yaml new file mode 100644 index 000000000..3de28b1a1 --- /dev/null +++ b/k8s/helm/apigwwm/templates/ocelot-cm.yaml @@ -0,0 +1,14 @@ +{{- $name := include "apigwwm.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "ocelot-{{ $name }}" + labels: + app: {{ template "apigwwm.name" . }} + chart: {{ template "apigwwm.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + {{ (.Files.Glob "configuration-web-marketing.json").AsConfig | indent 2 -}} + diff --git a/k8s/helm/apigwwm/templates/service.yaml b/k8s/helm/apigwwm/templates/service.yaml new file mode 100644 index 000000000..0ee3c4fb0 --- /dev/null +++ b/k8s/helm/apigwwm/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.webmarketingapigw }} + labels: + app: {{ template "apigwwm.name" . }} + chart: {{ template "apigwwm.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "apigwwm.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/apigwwm/values.yaml b/k8s/helm/apigwwm/values.yaml new file mode 100644 index 000000000..68cbb89c4 --- /dev/null +++ b/k8s/helm/apigwwm/values.yaml @@ -0,0 +1,64 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webmarketingapigw + +image: + repository: eshop/ocelotapigw + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: IdentityUrl + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 \ No newline at end of file diff --git a/k8s/helm/apigwws/.helmignore b/k8s/helm/apigwws/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/apigwws/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/apigwws/Chart.yaml b/k8s/helm/apigwws/Chart.yaml new file mode 100644 index 000000000..0a6c34e62 --- /dev/null +++ b/k8s/helm/apigwws/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: apigwws +version: 0.1.0 diff --git a/k8s/helm/apigwws/configuration-web-shopping.json b/k8s/helm/apigwws/configuration-web-shopping.json new file mode 100644 index 000000000..021056f43 --- /dev/null +++ b/k8s/helm/apigwws/configuration-web-shopping.json @@ -0,0 +1,154 @@ +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "catalog", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/c/{everything}", + "UpstreamHttpMethod": [ "GET" ] + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/b/{everything}", + "UpstreamHttpMethod": [], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "ordering", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/o/{everything}", + "UpstreamHttpMethod": [], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "webshoppingagg", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/{everything}", + "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "ordering", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/orders-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "ordering-signalrhub", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/hub/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/basket-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "catalog", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/catalog-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "marketing", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/marketing-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "payment", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/payment-api/{everything}", + "UpstreamHttpMethod": [] + }, + { + "DownstreamPathTemplate": "/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "locations.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/location-api/{everything}", + "UpstreamHttpMethod": [] + } + + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration" + } + } + \ No newline at end of file diff --git a/k8s/helm/apigwws/templates/NOTES.txt b/k8s/helm/apigwws/templates/NOTES.txt new file mode 100644 index 000000000..8214afb1e --- /dev/null +++ b/k8s/helm/apigwws/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop API Gateway for Web Shopping services installed +----------------------------------------------------- \ No newline at end of file diff --git a/k8s/helm/apigwws/templates/_helpers.tpl b/k8s/helm/apigwws/templates/_helpers.tpl new file mode 100644 index 000000000..b6aa6b483 --- /dev/null +++ b/k8s/helm/apigwws/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "apigwws.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "apigwws.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "apigwws.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/apigwws/templates/_names.tpl b/k8s/helm/apigwws/templates/_names.tpl new file mode 100644 index 000000000..a6eeb9965 --- /dev/null +++ b/k8s/helm/apigwws/templates/_names.tpl @@ -0,0 +1,53 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if $ctx.Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" $ctx -}} +{{- printf "/%s-%s" $name $suffix -}} +{{- else -}} +{{- printf "/%s" $name -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/apigwws/templates/configmap.yaml b/k8s/helm/apigwws/templates/configmap.yaml new file mode 100644 index 000000000..dd5530f61 --- /dev/null +++ b/k8s/helm/apigwws/templates/configmap.yaml @@ -0,0 +1,21 @@ +{{- $name := include "apigwws.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "apigwws.name" . }} + chart: {{ template "apigwws.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + diff --git a/k8s/helm/apigwws/templates/deployment.yaml b/k8s/helm/apigwws/templates/deployment.yaml new file mode 100644 index 000000000..4912d12bb --- /dev/null +++ b/k8s/helm/apigwws/templates/deployment.yaml @@ -0,0 +1,102 @@ +{{- $name := include "apigwws.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "apigwws.fullname" . }} + labels: + app: {{ template "apigwws.name" . }} + chart: {{ template "apigwws.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "apigwws.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "apigwws.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ $ocelotcfgname }} + items: + - key: configuration-web-shopping.json + path: configuration.json + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: config + mountPath: /app/configuration + env: + - name: PATH_BASE + value: {{ include "pathBase" (list .Values.app.ingress.entries.webshoppingapigw .) }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/apigwws/templates/ingress.yaml b/k8s/helm/apigwws/templates/ingress.yaml new file mode 100644 index 000000000..ee1f681ad --- /dev/null +++ b/k8s/helm/apigwws/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.webshoppingapigw .) -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "apigwws.fullname" . }} + labels: + app: {{ template "apigwws.name" . }} + chart: {{ template "apigwws.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.webshoppingapigw }} + servicePort: http +{{- end }} diff --git a/k8s/helm/apigwws/templates/ocelot-cm.yaml b/k8s/helm/apigwws/templates/ocelot-cm.yaml new file mode 100644 index 000000000..39b27f29a --- /dev/null +++ b/k8s/helm/apigwws/templates/ocelot-cm.yaml @@ -0,0 +1,14 @@ +{{- $name := include "apigwws.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "ocelot-{{ $name }}" + labels: + app: {{ template "apigwws.name" . }} + chart: {{ template "apigwws.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + {{ (.Files.Glob "configuration-web-shopping.json").AsConfig | indent 2 }} + diff --git a/k8s/helm/apigwws/templates/service.yaml b/k8s/helm/apigwws/templates/service.yaml new file mode 100644 index 000000000..5d74c2ad0 --- /dev/null +++ b/k8s/helm/apigwws/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.webshoppingapigw }} + labels: + app: {{ template "apigwws.name" . }} + chart: {{ template "apigwws.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "apigwws.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/apigwws/values.yaml b/k8s/helm/apigwws/values.yaml new file mode 100644 index 000000000..94b8a203f --- /dev/null +++ b/k8s/helm/apigwws/values.yaml @@ -0,0 +1,64 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webshoppingapigw + +image: + repository: eshop/ocelotapigw + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: IdentityUrl + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/app.yaml b/k8s/helm/app.yaml new file mode 100644 index 000000000..6b1c36922 --- /dev/null +++ b/k8s/helm/app.yaml @@ -0,0 +1,47 @@ +# This helm values file defines app-based settings +# Charts use those values, so this file **MUST** be included in all chart releases + + +app: # app global settings + name: "my-eshop" # Override for custom app name + ingress: # ingress related settings + entries: + basket: basket-api # ingress entry for basket api + catalog: catalog-api # ingress entry for catalog api + ordering: ordering-api # ingress entry for ordering api + identity: identity # ingress entry for identity api + mvc: webmvc # ingress entry for web mvc + spa: "" # ingress entry for web spa + status: webstatus # ingress entry for web status + webshoppingapigw: webshoppingapigw # ingress entry for web shopping Agw + webmarketingapigw: webmarketingapigw # ingress entry for web mkg Agw + mobilemarketingapigw: mobilemarketingapigw # ingress entry for mobile mkg Agw + mobileshoppingapigw: mobileshoppingapigw # ingress entry for mobile shopping Agw + webshoppingagg: webshoppingagg # ingress entry for web shopping aggregator + mobileshoppingagg: mobileshoppingagg # ingress entry for mobile shopping aggregator + payment: payment-api # ingress entry for payment api + locations: locations-api # ingress entry for locations api + marketing: marketing-api # ingress entry for marketing api + webhooks: webhooks-api # ingress entry for webhooks api + webhooksweb: webhooks-web # ingress entry for webhooks web demo client + svc: + basket: basket # service name for basket api + catalog: catalog # service name for catalog api + ordering: ordering # service name for ordering api + orderingbackgroundtasks: orderingbackgroundtasks # service name for orderingbackgroundtasks + orderingsignalrhub: ordering-signalrhub # service name for orderingsignalrhub + identity: identity # service name for identity api + mvc: webmvc # service name for web mvc + spa: webspa # service name for web spa + status: webstatus # service name for web status + webshoppingapigw: webshoppingapigw # service name for web shopping Agw + webmarketingapigw: webmarketingapigw # service name for web mkg Agw + mobilemarketingapigw: mobilemarketingapigw # service name for mobile mkg Agw + mobileshoppingapigw: mobileshoppingapigw # service name for mobile shopping Agw + webshoppingagg: webshoppingagg # service name for web shopping aggregator + mobileshoppingagg: mobileshoppingagg # service name for mobile shopping aggregator + payment: payment # service name for payment api + locations: locations # service name for locations api + marketing: marketing # service name for marketing ap + webhooks: webhooks # service name for webhooks api + webhooksweb: webhooksweb # service name for webhooks web diff --git a/k8s/helm/basket-api/.helmignore b/k8s/helm/basket-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/basket-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/basket-api/Chart.yaml b/k8s/helm/basket-api/Chart.yaml new file mode 100644 index 000000000..fd3e01486 --- /dev/null +++ b/k8s/helm/basket-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: basket-api +version: 0.1.0 diff --git a/k8s/helm/basket-api/templates/NOTES.txt b/k8s/helm/basket-api/templates/NOTES.txt new file mode 100644 index 000000000..8ba2c89ee --- /dev/null +++ b/k8s/helm/basket-api/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Basket API installed. +-------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "basket-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/basket-api/templates/_helpers.tpl b/k8s/helm/basket-api/templates/_helpers.tpl new file mode 100644 index 000000000..550eb2e6c --- /dev/null +++ b/k8s/helm/basket-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "basket-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "basket-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "basket-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/basket-api/templates/_names.tpl b/k8s/helm/basket-api/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/basket-api/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/basket-api/templates/configmap.yaml b/k8s/helm/basket-api/templates/configmap.yaml new file mode 100644 index 000000000..c851de359 --- /dev/null +++ b/k8s/helm/basket-api/templates/configmap.yaml @@ -0,0 +1,19 @@ +{{- $name := include "basket-api.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "basket-api.name" . }} + chart: {{ template "basket-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + basket__ConnectionString: {{ .Values.inf.redis.basket.constr }} + urls__IdentityUrl: http://{{ $identity }} + basket__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/basket-api/templates/deployment.yaml b/k8s/helm/basket-api/templates/deployment.yaml new file mode 100644 index 000000000..d96c0cacf --- /dev/null +++ b/k8s/helm/basket-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "basket-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "basket-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "basket-api.name" . }} + chart: {{ template "basket-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "basket-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "basket-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/basket-api/templates/service.yaml b/k8s/helm/basket-api/templates/service.yaml new file mode 100644 index 000000000..20224c3b5 --- /dev/null +++ b/k8s/helm/basket-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.basket }} + labels: + app: {{ template "basket-api.name" . }} + chart: {{ template "basket-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "basket-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/basket-api/values.yaml b/k8s/helm/basket-api/values.yaml new file mode 100644 index 000000000..6c264afba --- /dev/null +++ b/k8s/helm/basket-api/values.yaml @@ -0,0 +1,55 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /basket-api + +image: + repository: eshop/basket.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ConnectionString + key: basket__ConnectionString + - name: EventBusConnection + key: all__EventBusConnection + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: IdentityUrl + key: urls__IdentityUrl + - name: UseLoadTest + key: basket__EnableLoadTest + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/basket-data/.helmignore b/k8s/helm/basket-data/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/basket-data/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/basket-data/Chart.yaml b/k8s/helm/basket-data/Chart.yaml new file mode 100644 index 000000000..67ceddee1 --- /dev/null +++ b/k8s/helm/basket-data/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: basket-data +version: 0.1.0 diff --git a/k8s/helm/basket-data/templates/NOTES.txt b/k8s/helm/basket-data/templates/NOTES.txt new file mode 100644 index 000000000..c10513333 --- /dev/null +++ b/k8s/helm/basket-data/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Redis for keystore data installed +---------------------------------------- + +Redis is not directly exposed outside cluster. If need to access it from outside use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "basket-data.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/basket-data/templates/_helpers.tpl b/k8s/helm/basket-data/templates/_helpers.tpl new file mode 100644 index 000000000..74b51b089 --- /dev/null +++ b/k8s/helm/basket-data/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "basket-data.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "basket-data.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "basket-data.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/basket-data/templates/deployment.yaml b/k8s/helm/basket-data/templates/deployment.yaml new file mode 100644 index 000000000..8ccceceeb --- /dev/null +++ b/k8s/helm/basket-data/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "basket-data.fullname" . }} + labels: + app: {{ template "basket-data.name" . }} + chart: {{ template "basket-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "basket-data.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "basket-data.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 6379 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/k8s/helm/basket-data/templates/service.yaml b/k8s/helm/basket-data/templates/service.yaml new file mode 100644 index 000000000..98b8cc3bd --- /dev/null +++ b/k8s/helm/basket-data/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.inf.redis.basket.svc }} + labels: + app: {{ template "basket-data.name" . }} + chart: {{ template "basket-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "basket-data.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/basket-data/values.yaml b/k8s/helm/basket-data/values.yaml new file mode 100644 index 000000000..17cc75ee7 --- /dev/null +++ b/k8s/helm/basket-data/values.yaml @@ -0,0 +1,19 @@ +replicaCount: 1 + +image: + repository: redis + tag: 4.0.10 + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 6379 + + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/k8s/helm/catalog-api/.helmignore b/k8s/helm/catalog-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/catalog-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/catalog-api/Chart.yaml b/k8s/helm/catalog-api/Chart.yaml new file mode 100644 index 000000000..a143a0afe --- /dev/null +++ b/k8s/helm/catalog-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: catalog-api +version: 0.1.0 diff --git a/k8s/helm/catalog-api/templates/NOTES.txt b/k8s/helm/catalog-api/templates/NOTES.txt new file mode 100644 index 000000000..1f01a2b92 --- /dev/null +++ b/k8s/helm/catalog-api/templates/NOTES.txt @@ -0,0 +1,9 @@ +eShop Catalog API installed. +---------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "catalog-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 + diff --git a/k8s/helm/catalog-api/templates/_helpers.tpl b/k8s/helm/catalog-api/templates/_helpers.tpl new file mode 100644 index 000000000..6fd128e77 --- /dev/null +++ b/k8s/helm/catalog-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "catalog-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "catalog-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "catalog-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/catalog-api/templates/_names.tpl b/k8s/helm/catalog-api/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/catalog-api/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/catalog-api/templates/configmap.yaml b/k8s/helm/catalog-api/templates/configmap.yaml new file mode 100644 index 000000000..95d8f2f9b --- /dev/null +++ b/k8s/helm/catalog-api/templates/configmap.yaml @@ -0,0 +1,20 @@ +{{- $name := include "catalog-api.fullname" . -}} +{{- $sqlsrv := include "sql-name" . -}} +{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "catalog-api.name" . }} + chart: {{ template "catalog-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + catalog__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.catalog.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ + catalog__AzureStorageEnabled: "{{ .Values.inf.misc.useAzureStorage }}" + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/catalog-api/templates/deployment.yaml b/k8s/helm/catalog-api/templates/deployment.yaml new file mode 100644 index 000000000..d7a424a99 --- /dev/null +++ b/k8s/helm/catalog-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "catalog-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "catalog-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "catalog-api.name" . }} + chart: {{ template "catalog-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "catalog-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "catalog-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/catalog-api/templates/service.yaml b/k8s/helm/catalog-api/templates/service.yaml new file mode 100644 index 000000000..e63d4a4fc --- /dev/null +++ b/k8s/helm/catalog-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.catalog }} + labels: + app: {{ template "catalog-api.name" . }} + chart: {{ template "catalog-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "catalog-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/catalog-api/values.yaml b/k8s/helm/catalog-api/values.yaml new file mode 100644 index 000000000..836db6125 --- /dev/null +++ b/k8s/helm/catalog-api/values.yaml @@ -0,0 +1,59 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /catalog-api + +image: + repository: eshop/catalog.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ConnectionString + key: catalog__ConnectionString + - name: PicBaseUrl + key: catalog__PicBaseUrl + - name: AzureStorageEnabled + key: catalog__AzureStorageEnabled + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 + diff --git a/k8s/helm/deploy-all.ps1 b/k8s/helm/deploy-all.ps1 new file mode 100644 index 000000000..1819c9a67 --- /dev/null +++ b/k8s/helm/deploy-all.ps1 @@ -0,0 +1,89 @@ +Param( + [parameter(Mandatory=$false)][string]$registry, + [parameter(Mandatory=$false)][string]$dockerUser, + [parameter(Mandatory=$false)][string]$dockerPassword, + [parameter(Mandatory=$false)][string]$externalDns, + [parameter(Mandatory=$false)][string]$appName="eshop", + [parameter(Mandatory=$false)][bool]$deployInfrastructure=$true, + [parameter(Mandatory=$false)][bool]$clean=$true, + [parameter(Mandatory=$false)][string]$aksName="", + [parameter(Mandatory=$false)][string]$aksRg="", + [parameter(Mandatory=$false)][string]$imageTag="latest", + [parameter(Mandatory=$false)][bool]$useLocalk8s=$false + ) + +$dns = $externalDns + +$ingressValuesFile="ingress_values.yaml" + +if ($useLocalk8s -eq $true) { + $ingressValuesFile="ingress_values_dockerk8s.yaml" + $dns="localhost" +} + +if ($externalDns -eq "aks") { + if ([string]::IsNullOrEmpty($aksName) -or [string]::IsNullOrEmpty($aksRg)) { + Write-Host "Error: When using -dns aks, MUST set -aksName and -aksRg too." -ForegroundColor Red + exit 1 + } + Write-Host "Getting DNS of AKS of AKS $aksName (in resource group $aksRg)..." -ForegroundColor Green + $dns = $(az aks show -n $aksName -g $aksRg --query addonProfiles.httpApplicationRouting.config.HTTPApplicationRoutingZoneName) + if ([string]::IsNullOrEmpty($dns)) { + Write-Host "Error getting DNS of AKS $aksName (in resource group $aksRg). Please ensure AKS has httpRouting enabled AND Azure CLI is logged & in version 2.0.37 or higher" -ForegroundColor Red + exit 1 + } + $dns = $dns -replace '[\"]' + Write-Host "DNS base found is $dns. Will use $appName.$dns for the app!" -ForegroundColor Green + $dns = "$appName.$dns" +} + +# Initialization & check commands +if ([string]::IsNullOrEmpty($dns)) { + Write-Host "No DNS specified. Ingress resources will be bound to public ip" -ForegroundColor Yellow +} + +if ($clean) { + Write-Host "Cleaning previous helm releases..." -ForegroundColor Green + helm delete --purge $(helm ls -q) + Write-Host "Previous releases deleted" -ForegroundColor Green +} + +$useCustomRegistry=$false + +if (-not [string]::IsNullOrEmpty($registry)) { + $useCustomRegistry=$true + if ([string]::IsNullOrEmpty($dockerUser) -or [string]::IsNullOrEmpty($dockerPassword)) { + Write-Host "Error: Must use -dockerUser AND -dockerPassword if specifying custom registry" -ForegroundColor Red + exit 1 + } +} + +Write-Host "Begin eShopOnContainers installation using Helm" -ForegroundColor Green + +$infras = ("sql-data", "nosql-data", "rabbitmq", "keystore-data", "basket-data") +$charts = ("eshop-common", "apigwmm", "apigwms", "apigwwm", "apigwws", "basket-api","catalog-api", "identity-api", "locations-api", "marketing-api", "mobileshoppingagg","ordering-api","ordering-backgroundtasks","ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web") + +if ($deployInfrastructure) { + foreach ($infra in $infras) { + Write-Host "Installing infrastructure: $infra" -ForegroundColor Green + helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --name="$appName-$infra" $infra + } +} + +foreach ($chart in $charts) { + Write-Host "Installing: $chart" -ForegroundColor Green + if ($useCustomRegistry) { + helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart + } + else { + if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed + helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart + } + } +} + +Write-Host "helm charts installed." -ForegroundColor Green + + + + diff --git a/k8s/helm/eshop-common/.helmignore b/k8s/helm/eshop-common/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/eshop-common/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/eshop-common/Chart.yaml b/k8s/helm/eshop-common/Chart.yaml new file mode 100644 index 000000000..cd5e7b2fe --- /dev/null +++ b/k8s/helm/eshop-common/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: eshop-common +version: 0.1.0 diff --git a/k8s/helm/eshop-common/templates/NOTES.txt b/k8s/helm/eshop-common/templates/NOTES.txt new file mode 100644 index 000000000..1cc59f58a --- /dev/null +++ b/k8s/helm/eshop-common/templates/NOTES.txt @@ -0,0 +1,7 @@ +Common eShop resources installed: + +{{- if .Values.inf.registry -}} +* Docker registry secret ({{ .Values.inf.registry.secretName }}) +{{- end -}} + ++++ Done +++ \ No newline at end of file diff --git a/k8s/helm/eshop-common/templates/_helpers.tpl b/k8s/helm/eshop-common/templates/_helpers.tpl new file mode 100644 index 000000000..4a3c6324b --- /dev/null +++ b/k8s/helm/eshop-common/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "eshop-common.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "eshop-common.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "eshop-common.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/eshop-common/templates/_names.tpl b/k8s/helm/eshop-common/templates/_names.tpl new file mode 100644 index 000000000..7cdfb80d6 --- /dev/null +++ b/k8s/helm/eshop-common/templates/_names.tpl @@ -0,0 +1,3 @@ +{{- define "imagePullSecret" }} +{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.inf.registry.server (printf "%s:%s" .Values.inf.registry.login .Values.inf.registry.pwd | b64enc) | b64enc }} +{{- end }} \ No newline at end of file diff --git a/k8s/helm/eshop-common/templates/secret.yaml b/k8s/helm/eshop-common/templates/secret.yaml new file mode 100644 index 000000000..285ec85e7 --- /dev/null +++ b/k8s/helm/eshop-common/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.inf.registry -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.inf.registry.secretName }} +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ template "imagePullSecret" . }} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/eshop-common/values.yaml b/k8s/helm/eshop-common/values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/k8s/helm/identity-api/.helmignore b/k8s/helm/identity-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/identity-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/identity-api/Chart.yaml b/k8s/helm/identity-api/Chart.yaml new file mode 100644 index 000000000..7b9290ada --- /dev/null +++ b/k8s/helm/identity-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: identity-api +version: 0.1.0 diff --git a/k8s/helm/identity-api/templates/NOTES.txt b/k8s/helm/identity-api/templates/NOTES.txt new file mode 100644 index 000000000..48fbbe9b4 --- /dev/null +++ b/k8s/helm/identity-api/templates/NOTES.txt @@ -0,0 +1,4 @@ +eShop Identity API installed. +----------------------------- + +Access this API through ingress. \ No newline at end of file diff --git a/k8s/helm/identity-api/templates/_helpers.tpl b/k8s/helm/identity-api/templates/_helpers.tpl new file mode 100644 index 000000000..fb47187b4 --- /dev/null +++ b/k8s/helm/identity-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "identity-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "identity-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "identity-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/identity-api/templates/_names.tpl b/k8s/helm/identity-api/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/identity-api/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/identity-api/templates/configmap.yaml b/k8s/helm/identity-api/templates/configmap.yaml new file mode 100644 index 000000000..24d71b699 --- /dev/null +++ b/k8s/helm/identity-api/templates/configmap.yaml @@ -0,0 +1,40 @@ +{{- $name := include "identity-api.fullname" . -}} +{{- $sqlsrv := include "sql-name" . -}} +{{- $mvc_url := include "url-of" (list .Values.app.ingress.entries.mvc .) -}} +{{- $spa_url := include "url-of" (list .Values.app.ingress.entries.spa .) -}} +{{- $locations_url := include "url-of" (list .Values.app.ingress.entries.locations .) -}} +{{- $marketing_url := include "url-of" (list .Values.app.ingress.entries.marketing .) -}} +{{- $basket_url := include "url-of" (list .Values.app.ingress.entries.basket .) -}} +{{- $ordering_url := include "url-of" (list .Values.app.ingress.entries.ordering .) -}} +{{- $mobileshoppingagg := include "url-of" (list .Values.app.ingress.entries.mobileshoppingagg .) -}} +{{- $webhoppingagg := include "url-of" (list .Values.app.ingress.entries.webshoppingagg .) -}} +{{- $xamarincallback := include "url-of" (list "xamarincallback" .) -}} +{{- $webhooks_url := include "url-of" (list .Values.app.ingress.entries.webhooks .) -}} +{{- $webhooksweb_url := include "url-of" (list .Values.app.ingress.entries.webhooksweb .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "identity-api.name" . }} + chart: {{ template "identity-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + identity__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.identity.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + identity__keystore: {{ .Values.inf.redis.keystore.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + mvc_e: http://{{ $mvc_url }} + spa_e: http://{{ $spa_url }} + locations_e: http://{{ $locations_url }} + marketing_e: http://{{ $marketing_url }} + basket_e: http://{{ $basket_url }} + ordering_e: http://{{ $ordering_url }} + mobileshoppingagg_e: http://{{ $mobileshoppingagg }} + webshoppingagg_e: http://{{ $webhoppingagg }} + xamarin_callback_e: http://{{ $xamarincallback }} + webhooksapi_e: http://{{ $webhooks_url }} + webhooksweb_e: http://{{ $webhooksweb_url }} + + diff --git a/k8s/helm/identity-api/templates/deployment.yaml b/k8s/helm/identity-api/templates/deployment.yaml new file mode 100644 index 000000000..0a4ee2722 --- /dev/null +++ b/k8s/helm/identity-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "identity-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "identity-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "identity-api.name" . }} + chart: {{ template "identity-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "identity-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "identity-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/identity-api/templates/ingress.yaml b/k8s/helm/identity-api/templates/ingress.yaml new file mode 100644 index 000000000..5824f91e2 --- /dev/null +++ b/k8s/helm/identity-api/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "identity-api.fullname" . }} + labels: + app: {{ template "identity-api.name" . }} + chart: {{ template "identity-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.identity }} + servicePort: http +{{- end }} diff --git a/k8s/helm/identity-api/templates/service.yaml b/k8s/helm/identity-api/templates/service.yaml new file mode 100644 index 000000000..bca200389 --- /dev/null +++ b/k8s/helm/identity-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.identity }} + labels: + app: {{ template "identity-api.name" . }} + chart: {{ template "identity-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "identity-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/identity-api/values.yaml b/k8s/helm/identity-api/values.yaml new file mode 100644 index 000000000..c0fd38192 --- /dev/null +++ b/k8s/helm/identity-api/values.yaml @@ -0,0 +1,79 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /identity + +image: + repository: eshop/identity.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + hosts: + - chart-example.local + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +env: + urls: + configmap: + - name: ConnectionString + key: identity__ConnectionString + - name: DPConnectionString + key: identity__keystore + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: MvcClient + key: mvc_e + - name: SpaClient + key: spa_e + - name: LocationApiClient + key: locations_e + - name: MarketingApiClient + key: marketing_e + - name: BasketApiClient + key: basket_e + - name: OrderingApiClient + key: ordering_e + - name: MobileShoppingAggClient + key: mobileshoppingagg_e + - name: WebShoppingAggClient + key: webshoppingagg_e + - name: XamarinCallback + key: xamarin_callback_e + - name: WebhooksApiClient + key: webhooksapi_e + - name: WebhooksWebClient + key: webhooksweb_e + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + value: 'True' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 \ No newline at end of file diff --git a/k8s/helm/inf.yaml b/k8s/helm/inf.yaml new file mode 100644 index 000000000..b6ff102b0 --- /dev/null +++ b/k8s/helm/inf.yaml @@ -0,0 +1,50 @@ +# This heml values file defines all infrastructure used by eShopOnContainers. +# It is used on all charts, so ** MUST BE INCLUDED ** on every deployment + +inf: + sql: # inf.sql defines the sql server databases & logins +# host: my-sql-server # Uncomment to specify a custom sql-server to be used. By default "sql-data-" will be used + common: + user: sa # SQL user + pwd: Pass@word # SQL pwd + pid: Developer + catalog: # inf.sql.catalog: settings for the catalog-api sql (user, pwd, db) + db: CatalogDb # Catalog API SQL db name + ordering: # inf.sql.ordering: settings for the ordering-api sql (user, pwd, db) + db: OrderingDb # Ordering API SQL db name + identity: + db: IdentityDb # Ordering API SQL db name + marketing: + db: MarketingDb # Marketing API SQL db name + webhooks: + db: WebhooksDb # Webhooks DB + mongo: +# host: my-nosql-data # Uncomment to use specify custom mongo host. By default nosql-data is used + locations: + database: LocationsDb + marketing: + database: MarketingDb + redis: # inf.redis defines the redis' connection strings + basket: + svc: basket-data # Name of k8s svc for basket redis + constr: basket-data # Connection string to Redis used by Basket API + keystore: + svc: keystore-data # Name of k8s svc for keystore-data redis + constr: keystore-data # Connection string to Redis used as a Keystore (by Identity API) + eventbus: + svc: rabbitmq # Name of k8s svc for rabbitmq + constr: rabbitmq # Event bus connection string + useAzure: false # true if use Azure Service Bus. False if RabbitMQ + appinsights: + key: "" # App insights to use + k8s: # inf.k8s defines Kubernetes cluster global config + dns: "" # k8s external DNS. This value or ip value MUST BE PROVIDED + misc: # inf.misc contains miscellaneous configuration related to infrastructure + useLoadTest: false # If running under loading test or not + useAzureStorage: false # If catalog api uses azure storage or not +# registry: # Uncomment "registry" to specify registry secret +# secretName: # secretName is the name of the secret inside k8s +# server: # Registry login server +# login: # User login +# pwd: # User pwd + diff --git a/k8s/helm/ingress_values.yaml b/k8s/helm/ingress_values.yaml new file mode 100644 index 000000000..88540574d --- /dev/null +++ b/k8s/helm/ingress_values.yaml @@ -0,0 +1,5 @@ +ingress: + annotations: + kubernetes.io/ingress.class: addon-http-application-routing + ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/ssl-redirect: "false" diff --git a/k8s/helm/ingress_values_dockerk8s.yaml b/k8s/helm/ingress_values_dockerk8s.yaml new file mode 100644 index 000000000..75597aac9 --- /dev/null +++ b/k8s/helm/ingress_values_dockerk8s.yaml @@ -0,0 +1,5 @@ +ingress: + annotations: + kubernetes.io/ingress.class: "nginx" + ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/ssl-redirect: "false" diff --git a/k8s/helm/keystore-data/.helmignore b/k8s/helm/keystore-data/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/keystore-data/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/keystore-data/Chart.yaml b/k8s/helm/keystore-data/Chart.yaml new file mode 100644 index 000000000..0cfa515f9 --- /dev/null +++ b/k8s/helm/keystore-data/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: keystore-data +version: 0.1.0 diff --git a/k8s/helm/keystore-data/templates/NOTES.txt b/k8s/helm/keystore-data/templates/NOTES.txt new file mode 100644 index 000000000..bec3a1f0f --- /dev/null +++ b/k8s/helm/keystore-data/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Redis for keystore data installed +---------------------------------------- + +Redis is not directly exposed outside cluster. If need to access it from outside use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "keystore-data.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/keystore-data/templates/_helpers.tpl b/k8s/helm/keystore-data/templates/_helpers.tpl new file mode 100644 index 000000000..18786752f --- /dev/null +++ b/k8s/helm/keystore-data/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "keystore-data.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "keystore-data.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "keystore-data.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/keystore-data/templates/deployment.yaml b/k8s/helm/keystore-data/templates/deployment.yaml new file mode 100644 index 000000000..34f1fe074 --- /dev/null +++ b/k8s/helm/keystore-data/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "keystore-data.fullname" . }} + labels: + app: {{ template "keystore-data.name" . }} + chart: {{ template "keystore-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "keystore-data.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "keystore-data.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 6379 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/k8s/helm/keystore-data/templates/service.yaml b/k8s/helm/keystore-data/templates/service.yaml new file mode 100644 index 000000000..38e9a4273 --- /dev/null +++ b/k8s/helm/keystore-data/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.inf.redis.keystore.svc }} + labels: + app: {{ template "keystore-data.name" . }} + chart: {{ template "keystore-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "keystore-data.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/keystore-data/values.yaml b/k8s/helm/keystore-data/values.yaml new file mode 100644 index 000000000..17cc75ee7 --- /dev/null +++ b/k8s/helm/keystore-data/values.yaml @@ -0,0 +1,19 @@ +replicaCount: 1 + +image: + repository: redis + tag: 4.0.10 + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 6379 + + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/k8s/helm/locations-api/.helmignore b/k8s/helm/locations-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/locations-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/locations-api/Chart.yaml b/k8s/helm/locations-api/Chart.yaml new file mode 100644 index 000000000..5126fe847 --- /dev/null +++ b/k8s/helm/locations-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: locations-api +version: 0.1.0 diff --git a/k8s/helm/locations-api/templates/NOTES.txt b/k8s/helm/locations-api/templates/NOTES.txt new file mode 100644 index 000000000..3b48889bf --- /dev/null +++ b/k8s/helm/locations-api/templates/NOTES.txt @@ -0,0 +1,9 @@ +eShop Locations API installed. +------------------------------ + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "locations-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 + diff --git a/k8s/helm/locations-api/templates/_helpers.tpl b/k8s/helm/locations-api/templates/_helpers.tpl new file mode 100644 index 000000000..086a461ba --- /dev/null +++ b/k8s/helm/locations-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "locations-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "locations-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "locations-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/locations-api/templates/_names.tpl b/k8s/helm/locations-api/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/locations-api/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/locations-api/templates/configmap.yaml b/k8s/helm/locations-api/templates/configmap.yaml new file mode 100644 index 000000000..84881087d --- /dev/null +++ b/k8s/helm/locations-api/templates/configmap.yaml @@ -0,0 +1,22 @@ +{{- $name := include "locations-api.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $mongo := include "mongo-name" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "locations-api.name" . }} + chart: {{ template "locations-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + internalurls__IdentityUrl: http://{{ .Values.app.svc.identity }} + urls__IdentityUrl: {{ $identity }} + locations__ConnectionString: mongodb://{{ $mongo }} + locations__Database: {{ .Values.inf.mongo.locations.database }} \ No newline at end of file diff --git a/k8s/helm/locations-api/templates/deployment.yaml b/k8s/helm/locations-api/templates/deployment.yaml new file mode 100644 index 000000000..9667eb967 --- /dev/null +++ b/k8s/helm/locations-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "locations-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "locations-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "locations-api.name" . }} + chart: {{ template "locations-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "locations-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "locations-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/locations-api/templates/service.yaml b/k8s/helm/locations-api/templates/service.yaml new file mode 100644 index 000000000..abd628beb --- /dev/null +++ b/k8s/helm/locations-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.locations }} + labels: + app: {{ template "locations-api.name" . }} + chart: {{ template "locations-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "locations-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/locations-api/values.yaml b/k8s/helm/locations-api/values.yaml new file mode 100644 index 000000000..4718f2a0b --- /dev/null +++ b/k8s/helm/locations-api/values.yaml @@ -0,0 +1,66 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /locations-api + +image: + repository: eshop/locations.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: UseLoadTest + key: all_EnableLoadTest + - name: IdentityUrl + key: internalurls__IdentityUrl + - name: IdentityUrlExternal + key: urls__IdentityUrl + - name: ConnectionString + key: locations__ConnectionString + - name: Database + key: locations__Database + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/marketing-api/.helmignore b/k8s/helm/marketing-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/marketing-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/marketing-api/Chart.yaml b/k8s/helm/marketing-api/Chart.yaml new file mode 100644 index 000000000..173f94fd6 --- /dev/null +++ b/k8s/helm/marketing-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: marketing-api +version: 0.1.0 diff --git a/k8s/helm/marketing-api/templates/NOTES.txt b/k8s/helm/marketing-api/templates/NOTES.txt new file mode 100644 index 000000000..7fa66ed47 --- /dev/null +++ b/k8s/helm/marketing-api/templates/NOTES.txt @@ -0,0 +1,9 @@ +eShop Marketing API installed. +------------------------------ + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "marketing-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 + diff --git a/k8s/helm/marketing-api/templates/_helpers.tpl b/k8s/helm/marketing-api/templates/_helpers.tpl new file mode 100644 index 000000000..c252aeeac --- /dev/null +++ b/k8s/helm/marketing-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "marketing-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "marketing-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "marketing-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/marketing-api/templates/_names.tpl b/k8s/helm/marketing-api/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/marketing-api/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/marketing-api/templates/configmap.yaml b/k8s/helm/marketing-api/templates/configmap.yaml new file mode 100644 index 000000000..45f21e57d --- /dev/null +++ b/k8s/helm/marketing-api/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{- $name := include "marketing-api.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} +{{- $mongo := include "mongo-name" . -}} +{{- $sqlsrv := include "sql-name" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "marketing-api.name" . }} + chart: {{ template "marketing-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + internalurls__IdentityUrl: http://{{ .Values.app.svc.identity }} + urls__IdentityUrl: {{ $identity }} + marketing__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.marketing.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + marketing__MongoConnectionString: mongodb://{{ $mongo }} + marketing__MongoDatabase: {{ .Values.inf.mongo.marketing.database }} + marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ \ No newline at end of file diff --git a/k8s/helm/marketing-api/templates/deployment.yaml b/k8s/helm/marketing-api/templates/deployment.yaml new file mode 100644 index 000000000..c49026c1b --- /dev/null +++ b/k8s/helm/marketing-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "marketing-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "marketing-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "marketing-api.name" . }} + chart: {{ template "marketing-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "marketing-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "marketing-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/marketing-api/templates/service.yaml b/k8s/helm/marketing-api/templates/service.yaml new file mode 100644 index 000000000..0e9bfbea2 --- /dev/null +++ b/k8s/helm/marketing-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.marketing }} + labels: + app: {{ template "marketing-api.name" . }} + chart: {{ template "marketing-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "marketing-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/marketing-api/values.yaml b/k8s/helm/marketing-api/values.yaml new file mode 100644 index 000000000..00bebf27f --- /dev/null +++ b/k8s/helm/marketing-api/values.yaml @@ -0,0 +1,70 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /marketing-api + +image: + repository: eshop/marketing.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: UseLoadTest + key: all_EnableLoadTest + - name: IdentityUrl + key: internalurls__IdentityUrl + - name: IdentityUrlExternal + key: urls__IdentityUrl + - name: ConnectionString + key: marketing__ConnectionString + - name: MongoConnectionString + key: marketing__MongoConnectionString + - name: MongoDatabase + key: marketing__MongoDatabase + - name: PicBaseUrl + key: marketing__PicBaseUrl + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/mobileshoppingagg/.helmignore b/k8s/helm/mobileshoppingagg/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/mobileshoppingagg/Chart.yaml b/k8s/helm/mobileshoppingagg/Chart.yaml new file mode 100644 index 000000000..957edd619 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: mobileshoppingagg +version: 0.1.0 diff --git a/k8s/helm/mobileshoppingagg/templates/NOTES.txt b/k8s/helm/mobileshoppingagg/templates/NOTES.txt new file mode 100644 index 000000000..61971f717 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Mobile Marketing Aggregator is installed +---------------------------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "mobileshoppingagg.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/mobileshoppingagg/templates/_helpers.tpl b/k8s/helm/mobileshoppingagg/templates/_helpers.tpl new file mode 100644 index 000000000..b3aace0e7 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mobileshoppingagg.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mobileshoppingagg.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mobileshoppingagg.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/mobileshoppingagg/templates/_names.tpl b/k8s/helm/mobileshoppingagg/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/mobileshoppingagg/templates/configmap.yaml b/k8s/helm/mobileshoppingagg/templates/configmap.yaml new file mode 100644 index 000000000..d3e935409 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{- $name := include "mobileshoppingagg.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "mobileshoppingagg.name" . }} + chart: {{ template "mobileshoppingagg.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + mobileshoppingagg__keystore: {{ .Values.inf.redis.keystore.constr }} + internalurls__basket: http://{{ .Values.app.svc.basket }} + internalurls__catalog: http://{{ .Values.app.svc.catalog }} + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__ordering: http://{{ .Values.app.svc.ordering }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc diff --git a/k8s/helm/mobileshoppingagg/templates/deployment.yaml b/k8s/helm/mobileshoppingagg/templates/deployment.yaml new file mode 100644 index 000000000..0f23b3be6 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "mobileshoppingagg.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "mobileshoppingagg.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "mobileshoppingagg.name" . }} + chart: {{ template "mobileshoppingagg.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "mobileshoppingagg.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "mobileshoppingagg.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/mobileshoppingagg/templates/service.yaml b/k8s/helm/mobileshoppingagg/templates/service.yaml new file mode 100644 index 000000000..ef6726e88 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.mobileshoppingagg }} + labels: + app: {{ template "mobileshoppingagg.name" . }} + chart: {{ template "mobileshoppingagg.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "mobileshoppingagg.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/mobileshoppingagg/values.yaml b/k8s/helm/mobileshoppingagg/values.yaml new file mode 100644 index 000000000..fd26c7794 --- /dev/null +++ b/k8s/helm/mobileshoppingagg/values.yaml @@ -0,0 +1,78 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /mobileshoppingagg + +image: + repository: eshop/mobileshoppingagg + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: urls__basket + key: internalurls__basket + - name: urls__catalog + key: internalurls__catalog + - name: urls__orders + key: internalurls__ordering + - name: urls__identity + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: ASPNETCORE_URLS + value: http://0.0.0.0:80 + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + value: 'True' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/nosql-data/.helmignore b/k8s/helm/nosql-data/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/nosql-data/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/nosql-data/Chart.yaml b/k8s/helm/nosql-data/Chart.yaml new file mode 100644 index 000000000..848a11cbb --- /dev/null +++ b/k8s/helm/nosql-data/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: nosql-data +version: 0.1.0 diff --git a/k8s/helm/nosql-data/templates/NOTES.txt b/k8s/helm/nosql-data/templates/NOTES.txt new file mode 100644 index 000000000..116c3c4e0 --- /dev/null +++ b/k8s/helm/nosql-data/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop MongoDb Installed +----------------------- + +MongoDb is not exposed outside the cluster. If need to access it from outside, use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "nosql-data.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/nosql-data/templates/_helpers.tpl b/k8s/helm/nosql-data/templates/_helpers.tpl new file mode 100644 index 000000000..99be734f7 --- /dev/null +++ b/k8s/helm/nosql-data/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "nosql-data.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "nosql-data.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nosql-data.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/nosql-data/templates/_names.tpl b/k8s/helm/nosql-data/templates/_names.tpl new file mode 100644 index 000000000..56fb974fc --- /dev/null +++ b/k8s/helm/nosql-data/templates/_names.tpl @@ -0,0 +1,8 @@ + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} diff --git a/k8s/helm/nosql-data/templates/deployment.yaml b/k8s/helm/nosql-data/templates/deployment.yaml new file mode 100644 index 000000000..9b1f32319 --- /dev/null +++ b/k8s/helm/nosql-data/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "nosql-data.fullname" . }} + labels: + app: {{ template "nosql-data.name" . }} + chart: {{ template "nosql-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "nosql-data.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "nosql-data.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 27017 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/k8s/helm/nosql-data/templates/service.yaml b/k8s/helm/nosql-data/templates/service.yaml new file mode 100644 index 000000000..478cadfea --- /dev/null +++ b/k8s/helm/nosql-data/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "mongo-name" . }} + labels: + app: {{ template "nosql-data.name" . }} + chart: {{ template "nosql-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "nosql-data.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/nosql-data/values.yaml b/k8s/helm/nosql-data/values.yaml new file mode 100644 index 000000000..1a380e6b4 --- /dev/null +++ b/k8s/helm/nosql-data/values.yaml @@ -0,0 +1,19 @@ +replicaCount: 1 + +image: + repository: mongo + tag: 3.6.5-jessie + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 27017 + + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/k8s/helm/ordering-api/.helmignore b/k8s/helm/ordering-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/ordering-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/ordering-api/Chart.yaml b/k8s/helm/ordering-api/Chart.yaml new file mode 100644 index 000000000..b65ca4b9a --- /dev/null +++ b/k8s/helm/ordering-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: ordering-api +version: 0.1.0 diff --git a/k8s/helm/ordering-api/templates/NOTES.txt b/k8s/helm/ordering-api/templates/NOTES.txt new file mode 100644 index 000000000..43bfd2fdf --- /dev/null +++ b/k8s/helm/ordering-api/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Ordering API installed. +----------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "ordering-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/ordering-api/templates/_helpers.tpl b/k8s/helm/ordering-api/templates/_helpers.tpl new file mode 100644 index 000000000..978c08c64 --- /dev/null +++ b/k8s/helm/ordering-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "ordering-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ordering-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ordering-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/ordering-api/templates/_names.tpl b/k8s/helm/ordering-api/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/ordering-api/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/ordering-api/templates/configmap.yaml b/k8s/helm/ordering-api/templates/configmap.yaml new file mode 100644 index 000000000..de4cb2d7a --- /dev/null +++ b/k8s/helm/ordering-api/templates/configmap.yaml @@ -0,0 +1,20 @@ +{{- $name := include "ordering-api.fullname" . -}} +{{- $sqlsrv := include "sql-name" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "ordering-api.name" . }} + chart: {{ template "ordering-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + ordering__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + urls__IdentityUrl: http://{{ $identity }} + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/ordering-api/templates/deployment.yaml b/k8s/helm/ordering-api/templates/deployment.yaml new file mode 100644 index 000000000..a99ccdc28 --- /dev/null +++ b/k8s/helm/ordering-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "ordering-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "ordering-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "ordering-api.name" . }} + chart: {{ template "ordering-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "ordering-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "ordering-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/ordering-api/templates/service.yaml b/k8s/helm/ordering-api/templates/service.yaml new file mode 100644 index 000000000..bedfd6f01 --- /dev/null +++ b/k8s/helm/ordering-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.ordering }} + labels: + app: {{ template "ordering-api.name" . }} + chart: {{ template "ordering-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "ordering-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/ordering-api/values.yaml b/k8s/helm/ordering-api/values.yaml new file mode 100644 index 000000000..c717d2793 --- /dev/null +++ b/k8s/helm/ordering-api/values.yaml @@ -0,0 +1,64 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /ordering-api + +image: + repository: eshop/ordering.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + hosts: + - chart-example.local + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ConnectionString + key: ordering__ConnectionString + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: UseLoadTest + key: ordering__EnableLoadTest + - name: IdentityUrl + key: urls__IdentityUrl + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/ordering-backgroundtasks/.helmignore b/k8s/helm/ordering-backgroundtasks/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/ordering-backgroundtasks/Chart.yaml b/k8s/helm/ordering-backgroundtasks/Chart.yaml new file mode 100644 index 000000000..6ad4f47e6 --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: ordering-backgroundtasks +version: 0.1.0 diff --git a/k8s/helm/ordering-backgroundtasks/templates/NOTES.txt b/k8s/helm/ordering-backgroundtasks/templates/NOTES.txt new file mode 100644 index 000000000..54e1b49ea --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/NOTES.txt @@ -0,0 +1,3 @@ +eShop Ordering Background Tasks installed. +------------------------------------------ + diff --git a/k8s/helm/ordering-backgroundtasks/templates/_helpers.tpl b/k8s/helm/ordering-backgroundtasks/templates/_helpers.tpl new file mode 100644 index 000000000..e61b78285 --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "ordering-backgroundtasks.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ordering-backgroundtasks.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ordering-backgroundtasks.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/ordering-backgroundtasks/templates/_names.tpl b/k8s/helm/ordering-backgroundtasks/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml b/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml new file mode 100644 index 000000000..54fec785b --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml @@ -0,0 +1,20 @@ +{{- $name := include "ordering-backgroundtasks.fullname" . -}} +{{- $sqlsrv := include "sql-name" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "ordering-backgroundtasks.name" . }} + chart: {{ template "ordering-backgroundtasks.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + ordering__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + graceperiodmanager__CheckUpdateTime: "{{ .Values.cfg.checkUpdateTime }}" + graceperiodmanager__GracePeriodTime: "{{ .Values.cfg.gracePeriodTime }}" \ No newline at end of file diff --git a/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml b/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml new file mode 100644 index 000000000..017f9f3dd --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "ordering-backgroundtasks.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "ordering-backgroundtasks.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "ordering-backgroundtasks.name" . }} + chart: {{ template "ordering-backgroundtasks.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "ordering-backgroundtasks.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "ordering-backgroundtasks.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/ordering-backgroundtasks/templates/service.yaml b/k8s/helm/ordering-backgroundtasks/templates/service.yaml new file mode 100644 index 000000000..d8fcba036 --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.orderingbackgroundtasks }} + labels: + app: {{ template "ordering-backgroundtasks.name" . }} + chart: {{ template "ordering-backgroundtasks.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "ordering-backgroundtasks.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/ordering-backgroundtasks/values.yaml b/k8s/helm/ordering-backgroundtasks/values.yaml new file mode 100644 index 000000000..d065f0345 --- /dev/null +++ b/k8s/helm/ordering-backgroundtasks/values.yaml @@ -0,0 +1,70 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /ordering-backgroundtasks + +image: + repository: eshop/ordering.backgroundtasks + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + hosts: + - chart-example.local + tls: [] + +cfg: + checkUpdateTime: "15000" + gracePeriodTime: "1" + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ConnectionString + key: ordering__ConnectionString + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: UseLoadTest + key: ordering__EnableLoadTest + - name: CheckUpdateTime + key: graceperiodmanager__CheckUpdateTime + - name: GracePeriodTime + key: graceperiodmanager__GracePeriodTime + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/ordering-signalrhub/.helmignore b/k8s/helm/ordering-signalrhub/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/ordering-signalrhub/Chart.yaml b/k8s/helm/ordering-signalrhub/Chart.yaml new file mode 100644 index 000000000..d43e83bf0 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: ordering-signalrhub +version: 0.1.0 diff --git a/k8s/helm/ordering-signalrhub/templates/NOTES.txt b/k8s/helm/ordering-signalrhub/templates/NOTES.txt new file mode 100644 index 000000000..fc55c9dfa --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Ordering SignalR Hub installed +------------------------------------ + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "ordering-signalrhub.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/ordering-signalrhub/templates/_helpers.tpl b/k8s/helm/ordering-signalrhub/templates/_helpers.tpl new file mode 100644 index 000000000..2c11ddb51 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "ordering-signalrhub.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ordering-signalrhub.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ordering-signalrhub.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/ordering-signalrhub/templates/_names.tpl b/k8s/helm/ordering-signalrhub/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/ordering-signalrhub/templates/configmap.yaml b/k8s/helm/ordering-signalrhub/templates/configmap.yaml new file mode 100644 index 000000000..addcf7e9d --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/configmap.yaml @@ -0,0 +1,18 @@ +{{- $name := include "ordering-signalrhub.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "ordering-signalrhub.name" . }} + chart: {{ template "ordering-signalrhub.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + signalr__StoreConnectionString: {{ .Values.inf.redis.keystore.constr }} + urls__IdentityUrl: http://{{ $identity }} \ No newline at end of file diff --git a/k8s/helm/ordering-signalrhub/templates/deployment.yaml b/k8s/helm/ordering-signalrhub/templates/deployment.yaml new file mode 100644 index 000000000..af3867ea5 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/deployment.yaml @@ -0,0 +1,70 @@ +{{- $name := include "ordering-signalrhub.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "ordering-signalrhub.fullname" . }} + labels: + app: {{ template "ordering-signalrhub.name" . }} + chart: {{ template "ordering-signalrhub.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "ordering-signalrhub.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "ordering-signalrhub.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/ordering-signalrhub/templates/service.yaml b/k8s/helm/ordering-signalrhub/templates/service.yaml new file mode 100644 index 000000000..501539923 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.orderingsignalrhub }} + labels: + app: {{ template "ordering-signalrhub.name" . }} + chart: {{ template "ordering-signalrhub.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "ordering-signalrhub.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/ordering-signalrhub/values.yaml b/k8s/helm/ordering-signalrhub/values.yaml new file mode 100644 index 000000000..19099b147 --- /dev/null +++ b/k8s/helm/ordering-signalrhub/values.yaml @@ -0,0 +1,57 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /ordering-signalrhub + +image: + repository: eshop/ordering.signalrhub + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + hosts: + - chart-example.local + tls: [] + +cfg: + checkUpdateTime: "15000" + gracePeriodTime: "1" + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: IdentityUrl + key: urls__IdentityUrl + - name: SignalrStoreConnectionString + key: signalr__StoreConnectionString + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + values: 'True' + diff --git a/k8s/helm/payment-api/.helmignore b/k8s/helm/payment-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/payment-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/payment-api/Chart.yaml b/k8s/helm/payment-api/Chart.yaml new file mode 100644 index 000000000..b7dba9341 --- /dev/null +++ b/k8s/helm/payment-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: payment-api +version: 0.1.0 diff --git a/k8s/helm/payment-api/templates/NOTES.txt b/k8s/helm/payment-api/templates/NOTES.txt new file mode 100644 index 000000000..6d178f344 --- /dev/null +++ b/k8s/helm/payment-api/templates/NOTES.txt @@ -0,0 +1,9 @@ +eShop Payment API installed. +---------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "payment-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 + diff --git a/k8s/helm/payment-api/templates/_helpers.tpl b/k8s/helm/payment-api/templates/_helpers.tpl new file mode 100644 index 000000000..2f98d7ea2 --- /dev/null +++ b/k8s/helm/payment-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "payment-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "payment-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "payment-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/payment-api/templates/_names.tpl b/k8s/helm/payment-api/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/payment-api/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/payment-api/templates/configmap.yaml b/k8s/helm/payment-api/templates/configmap.yaml new file mode 100644 index 000000000..6717705b5 --- /dev/null +++ b/k8s/helm/payment-api/templates/configmap.yaml @@ -0,0 +1,15 @@ +{{- $name := include "payment-api.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "payment-api.name" . }} + chart: {{ template "payment-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/payment-api/templates/deployment.yaml b/k8s/helm/payment-api/templates/deployment.yaml new file mode 100644 index 000000000..8b01f7394 --- /dev/null +++ b/k8s/helm/payment-api/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "payment-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "payment-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "payment-api.name" . }} + chart: {{ template "payment-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "payment-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "payment-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/payment-api/templates/service.yaml b/k8s/helm/payment-api/templates/service.yaml new file mode 100644 index 000000000..14fc7479c --- /dev/null +++ b/k8s/helm/payment-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.payment }} + labels: + app: {{ template "payment-api.name" . }} + chart: {{ template "payment-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "payment-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/payment-api/values.yaml b/k8s/helm/payment-api/values.yaml new file mode 100644 index 000000000..341e4e1a9 --- /dev/null +++ b/k8s/helm/payment-api/values.yaml @@ -0,0 +1,56 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /payment-api + +image: + repository: eshop/payment.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 diff --git a/k8s/helm/rabbitmq/.helmignore b/k8s/helm/rabbitmq/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/rabbitmq/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/rabbitmq/Chart.yaml b/k8s/helm/rabbitmq/Chart.yaml new file mode 100644 index 000000000..2d955858e --- /dev/null +++ b/k8s/helm/rabbitmq/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: rabbitmq +version: 0.1.0 diff --git a/k8s/helm/rabbitmq/templates/NOTES.txt b/k8s/helm/rabbitmq/templates/NOTES.txt new file mode 100644 index 000000000..49edf7f9c --- /dev/null +++ b/k8s/helm/rabbitmq/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop rabbitmq installed +------------------------- + +rabbitmq is not directly exposed outside cluster. If need to access it from outside use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rabbitmq.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/rabbitmq/templates/_helpers.tpl b/k8s/helm/rabbitmq/templates/_helpers.tpl new file mode 100644 index 000000000..bbbb2e33d --- /dev/null +++ b/k8s/helm/rabbitmq/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "rabbitmq.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "rabbitmq.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "rabbitmq.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/rabbitmq/templates/_names.tpl b/k8s/helm/rabbitmq/templates/_names.tpl new file mode 100644 index 000000000..be0a9b800 --- /dev/null +++ b/k8s/helm/rabbitmq/templates/_names.tpl @@ -0,0 +1,8 @@ + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "rabbitmq" -}} +{{- end -}} +{{- end -}} diff --git a/k8s/helm/rabbitmq/templates/deployment.yaml b/k8s/helm/rabbitmq/templates/deployment.yaml new file mode 100644 index 000000000..9819a6455 --- /dev/null +++ b/k8s/helm/rabbitmq/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "rabbitmq.fullname" . }} + labels: + app: {{ template "rabbitmq.name" . }} + chart: {{ template "rabbitmq.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "rabbitmq.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "rabbitmq.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 5672 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/k8s/helm/rabbitmq/templates/service.yaml b/k8s/helm/rabbitmq/templates/service.yaml new file mode 100644 index 000000000..5de39e0a8 --- /dev/null +++ b/k8s/helm/rabbitmq/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.inf.eventbus.svc }} + labels: + app: {{ template "rabbitmq.name" . }} + chart: {{ template "rabbitmq.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "rabbitmq.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/rabbitmq/values.yaml b/k8s/helm/rabbitmq/values.yaml new file mode 100644 index 000000000..5e9efd521 --- /dev/null +++ b/k8s/helm/rabbitmq/values.yaml @@ -0,0 +1,19 @@ +replicaCount: 1 + +image: + repository: rabbitmq + tag: 3-management + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 5672 + + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/k8s/helm/sql-data/.helmignore b/k8s/helm/sql-data/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/sql-data/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/sql-data/Chart.yaml b/k8s/helm/sql-data/Chart.yaml new file mode 100644 index 000000000..6e5d726c5 --- /dev/null +++ b/k8s/helm/sql-data/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: sql-data +version: 0.1.0 diff --git a/k8s/helm/sql-data/templates/NOTES.txt b/k8s/helm/sql-data/templates/NOTES.txt new file mode 100644 index 000000000..468a155b0 --- /dev/null +++ b/k8s/helm/sql-data/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop SQL Server Installed +-------------------------- + +SQL server is not exposed outside the cluster. If need to access it from outside, use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "sql-data.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 \ No newline at end of file diff --git a/k8s/helm/sql-data/templates/_helpers.tpl b/k8s/helm/sql-data/templates/_helpers.tpl new file mode 100644 index 000000000..ee953f2f8 --- /dev/null +++ b/k8s/helm/sql-data/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "sql-data.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sql-data.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sql-data.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/sql-data/templates/_names.tpl b/k8s/helm/sql-data/templates/_names.tpl new file mode 100644 index 000000000..dc35d62fe --- /dev/null +++ b/k8s/helm/sql-data/templates/_names.tpl @@ -0,0 +1,8 @@ + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/sql-data/templates/deployment.yaml b/k8s/helm/sql-data/templates/deployment.yaml new file mode 100644 index 000000000..4b2f589ef --- /dev/null +++ b/k8s/helm/sql-data/templates/deployment.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "sql-data.fullname" . }} + labels: + app: {{ template "sql-data.name" . }} + chart: {{ template "sql-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "sql-data.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "sql-data.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: ACCEPT_EULA + value: "Y" + - name: MSSQL_PID + value: {{ .Values.inf.sql.common.pid }} + - name: MSSQL_SA_PASSWORD + value: {{ .Values.inf.sql.common.pwd }} + ports: + - name: http + containerPort: 1433 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/k8s/helm/sql-data/templates/service.yaml b/k8s/helm/sql-data/templates/service.yaml new file mode 100644 index 000000000..b9b8d59fc --- /dev/null +++ b/k8s/helm/sql-data/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "sql-name" . }} + labels: + app: {{ template "sql-data.name" . }} + chart: {{ template "sql-data.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "sql-data.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/sql-data/values.yaml b/k8s/helm/sql-data/values.yaml new file mode 100644 index 000000000..0ed76556a --- /dev/null +++ b/k8s/helm/sql-data/values.yaml @@ -0,0 +1,19 @@ +replicaCount: 1 + +image: + repository: microsoft/mssql-server-linux + tag: 2017-CU7 + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 1433 + + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/k8s/helm/webhooks-api/.helmignore b/k8s/helm/webhooks-api/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webhooks-api/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webhooks-api/Chart.yaml b/k8s/helm/webhooks-api/Chart.yaml new file mode 100644 index 000000000..f8e950782 --- /dev/null +++ b/k8s/helm/webhooks-api/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webhooks-api +version: 0.1.0 diff --git a/k8s/helm/webhooks-api/templates/NOTES.txt b/k8s/helm/webhooks-api/templates/NOTES.txt new file mode 100644 index 000000000..818b99d1b --- /dev/null +++ b/k8s/helm/webhooks-api/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Ordering API installed. +----------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "webhooks-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/webhooks-api/templates/_helpers.tpl b/k8s/helm/webhooks-api/templates/_helpers.tpl new file mode 100644 index 000000000..3742516b7 --- /dev/null +++ b/k8s/helm/webhooks-api/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webhooks-api.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webhooks-api.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webhooks-api.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webhooks-api/templates/_names.tpl b/k8s/helm/webhooks-api/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/webhooks-api/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webhooks-api/templates/configmap.yaml b/k8s/helm/webhooks-api/templates/configmap.yaml new file mode 100644 index 000000000..a18126858 --- /dev/null +++ b/k8s/helm/webhooks-api/templates/configmap.yaml @@ -0,0 +1,20 @@ +{{- $name := include "webhooks-api.fullname" . -}} +{{- $sqlsrv := include "sql-name" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webhooks-api.name" . }} + chart: {{ template "webhooks-api.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + webhooks__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.webhooks.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; + urls__IdentityUrl: http://{{ $identity }} + urls__IdentityUrlExternal: http://{{ $identity }} + all__EventBusConnection: {{ .Values.inf.eventbus.constr }} + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/webhooks-api/templates/deployment.yaml b/k8s/helm/webhooks-api/templates/deployment.yaml new file mode 100644 index 000000000..9eef1d6f1 --- /dev/null +++ b/k8s/helm/webhooks-api/templates/deployment.yaml @@ -0,0 +1,71 @@ +{{- $name := include "webhooks-api.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webhooks-api.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webhooks-api.name" . }} + chart: {{ template "webhooks-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webhooks-api.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webhooks-api.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webhooks-api/templates/ingress.yaml b/k8s/helm/webhooks-api/templates/ingress.yaml new file mode 100644 index 000000000..293f8e47e --- /dev/null +++ b/k8s/helm/webhooks-api/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "webhooks-api.fullname" . }} + labels: + app: {{ template "webhooks-api.name" . }} + chart: {{ template "webhooks-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.webhooks }} + servicePort: http +{{- end }} diff --git a/k8s/helm/webhooks-api/templates/service.yaml b/k8s/helm/webhooks-api/templates/service.yaml new file mode 100644 index 000000000..d8a02ba65 --- /dev/null +++ b/k8s/helm/webhooks-api/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.webhooks }} + labels: + app: {{ template "webhooks-api.name" . }} + chart: {{ template "webhooks-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webhooks-api.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webhooks-api/values.yaml b/k8s/helm/webhooks-api/values.yaml new file mode 100644 index 000000000..f6b1957e9 --- /dev/null +++ b/k8s/helm/webhooks-api/values.yaml @@ -0,0 +1,53 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webhooks-api + +image: + repository: eshop/webhooks.api + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + hosts: + - chart-example.local + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ConnectionString + key: webhooks__ConnectionString + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: EventBusConnection + key: all__EventBusConnection + - name: AzureServiceBusEnabled + key: all__UseAzureServiceBus + - name: IdentityUrl + key: urls__IdentityUrl + - name: IdentityUrlExternal + key: urls__IdentityUrlExternal + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' + diff --git a/k8s/helm/webhooks-web/.helmignore b/k8s/helm/webhooks-web/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webhooks-web/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webhooks-web/Chart.yaml b/k8s/helm/webhooks-web/Chart.yaml new file mode 100644 index 000000000..420b4f16d --- /dev/null +++ b/k8s/helm/webhooks-web/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webhooks-web +version: 0.1.0 diff --git a/k8s/helm/webhooks-web/templates/NOTES.txt b/k8s/helm/webhooks-web/templates/NOTES.txt new file mode 100644 index 000000000..b7f7f97ba --- /dev/null +++ b/k8s/helm/webhooks-web/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Ordering API installed. +----------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "webhooks-web.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/webhooks-web/templates/_helpers.tpl b/k8s/helm/webhooks-web/templates/_helpers.tpl new file mode 100644 index 000000000..cbc856713 --- /dev/null +++ b/k8s/helm/webhooks-web/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webhooks-web.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webhooks-web.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webhooks-web.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webhooks-web/templates/_names.tpl b/k8s/helm/webhooks-web/templates/_names.tpl new file mode 100644 index 000000000..39ee485ef --- /dev/null +++ b/k8s/helm/webhooks-web/templates/_names.tpl @@ -0,0 +1,51 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webhooks-web/templates/configmap.yaml b/k8s/helm/webhooks-web/templates/configmap.yaml new file mode 100644 index 000000000..8852c7586 --- /dev/null +++ b/k8s/helm/webhooks-web/templates/configmap.yaml @@ -0,0 +1,19 @@ +{{- $name := include "webhooks-web.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $webhooksweb := include "url-of" (list .Values.app.ingress.entries.webhooksweb .) -}} +{{- $webhooks := include "url-of" (list .Values.app.ingress.entries.webhooks .) -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webhooks-web.name" . }} + chart: {{ template "webhooks-web.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + urls__webhooks: http://{{ $webhooks }} + identity_e: http://{{ $identity }} + webhooksweb_e: http://{{ $webhooksweb }} + urls_webhooksweb: http://{{ .Values.app.svc.webhooksweb }} diff --git a/k8s/helm/webhooks-web/templates/deployment.yaml b/k8s/helm/webhooks-web/templates/deployment.yaml new file mode 100644 index 000000000..4c930124a --- /dev/null +++ b/k8s/helm/webhooks-web/templates/deployment.yaml @@ -0,0 +1,71 @@ +{{- $name := include "webhooks-web.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webhooks-web.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webhooks-web.name" . }} + chart: {{ template "webhooks-web.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webhooks-web.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webhooks-web.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webhooks-web/templates/ingress.yaml b/k8s/helm/webhooks-web/templates/ingress.yaml new file mode 100644 index 000000000..e725999f0 --- /dev/null +++ b/k8s/helm/webhooks-web/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "webhooks-web.fullname" . }} + labels: + app: {{ template "webhooks-web.name" . }} + chart: {{ template "webhooks-web.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.webhooksweb }} + servicePort: http +{{- end }} diff --git a/k8s/helm/webhooks-web/templates/service.yaml b/k8s/helm/webhooks-web/templates/service.yaml new file mode 100644 index 000000000..873ebcc0e --- /dev/null +++ b/k8s/helm/webhooks-web/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.webhooksweb }} + labels: + app: {{ template "webhooks-web.name" . }} + chart: {{ template "webhooks-web.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webhooks-web.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webhooks-web/values.yaml b/k8s/helm/webhooks-web/values.yaml new file mode 100644 index 000000000..0e5b04b57 --- /dev/null +++ b/k8s/helm/webhooks-web/values.yaml @@ -0,0 +1,52 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webhooks-web + +image: + repository: eshop/webhooks.client + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + hosts: + - chart-example.local + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: WebhooksUrl + key: urls__webhooks + - name: IdentityUrl + key: identity_e + - name: CallbackUrl + key: webhooksweb_e + - name: SelfUrl + key: webhooksweb_e + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Production + - name: OrchestratorType + value: 'K8S' + - name: Token + value: "WebHooks-Demo-Web" # Can use whatever you want + + diff --git a/k8s/helm/webmvc/.helmignore b/k8s/helm/webmvc/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webmvc/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webmvc/Chart.yaml b/k8s/helm/webmvc/Chart.yaml new file mode 100644 index 000000000..c63e8924a --- /dev/null +++ b/k8s/helm/webmvc/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webmvc +version: 0.1.0 diff --git a/k8s/helm/webmvc/templates/NOTES.txt b/k8s/helm/webmvc/templates/NOTES.txt new file mode 100644 index 000000000..06e02a45d --- /dev/null +++ b/k8s/helm/webmvc/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop WebMVC installed. +----------------------- diff --git a/k8s/helm/webmvc/templates/_helpers.tpl b/k8s/helm/webmvc/templates/_helpers.tpl new file mode 100644 index 000000000..2e3bcef56 --- /dev/null +++ b/k8s/helm/webmvc/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webmvc.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webmvc.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webmvc.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webmvc/templates/_names.tpl b/k8s/helm/webmvc/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/webmvc/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webmvc/templates/configmap.yaml b/k8s/helm/webmvc/templates/configmap.yaml new file mode 100644 index 000000000..60dacdadd --- /dev/null +++ b/k8s/helm/webmvc/templates/configmap.yaml @@ -0,0 +1,29 @@ +{{- $name := include "webmvc.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} +{{- $mvc := include "url-of" (list .Values.app.ingress.entries.mvc .) -}} +{{- $mongo := include "mongo-name" . -}} + + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webmvc.name" . }} + chart: {{ template "webmvc.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + webmvc__keystore: {{ .Values.inf.redis.keystore.constr }} + internalurls__apigwws: http://{{ .Values.app.svc.webshoppingapigw }} + internalurls__apigwwm: http://{{ .Values.app.svc.webmarketingapigw }} + internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc + urls__apigwws: http://{{ $webshoppingapigw }} + urls__mvc: http://{{ $mvc }} + urls__IdentityUrl: http://{{ $identity }} diff --git a/k8s/helm/webmvc/templates/deployment.yaml b/k8s/helm/webmvc/templates/deployment.yaml new file mode 100644 index 000000000..d972db448 --- /dev/null +++ b/k8s/helm/webmvc/templates/deployment.yaml @@ -0,0 +1,71 @@ +{{- $name := include "webmvc.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webmvc.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webmvc.name" . }} + chart: {{ template "webmvc.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webmvc.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webmvc.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webmvc/templates/ingress.yaml b/k8s/helm/webmvc/templates/ingress.yaml new file mode 100644 index 000000000..abfb62b2f --- /dev/null +++ b/k8s/helm/webmvc/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "webmvc.fullname" . }} + labels: + app: {{ template "webmvc.name" . }} + chart: {{ template "webmvc.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.mvc }} + servicePort: http +{{- end }} diff --git a/k8s/helm/webmvc/templates/service.yaml b/k8s/helm/webmvc/templates/service.yaml new file mode 100644 index 000000000..74d87673f --- /dev/null +++ b/k8s/helm/webmvc/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.mvc }} + labels: + app: {{ template "webmvc.name" . }} + chart: {{ template "webmvc.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webmvc.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webmvc/values.yaml b/k8s/helm/webmvc/values.yaml new file mode 100644 index 000000000..f4d077fc2 --- /dev/null +++ b/k8s/helm/webmvc/values.yaml @@ -0,0 +1,65 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webmvc + +image: + repository: eshop/webmvc + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: UseLoadTest + key: all_EnableLoadTest + - name: DPConnectionString + key: webmvc__keystore + - name: PurchaseUrl + key: internalurls__apigwws + - name: ExternalPurchaseUrl + key: urls__apigwws + - name: CallBackUrl + key: urls__mvc + - name: IdentityUrl + key: urls__IdentityUrl + - name: MarketingUrl + key: internalurls__apigwwm + - name: PurchaseUrlHC + key: internalurls__apigwws__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: MarketingUrlHC + key: internalurls__apigwwm__hc + - name: SignalrHubUrl + key: urls__apigwws + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + value: 'True' + diff --git a/k8s/helm/webshoppingagg/.helmignore b/k8s/helm/webshoppingagg/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webshoppingagg/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webshoppingagg/Chart.yaml b/k8s/helm/webshoppingagg/Chart.yaml new file mode 100644 index 000000000..cd7541025 --- /dev/null +++ b/k8s/helm/webshoppingagg/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webshoppingagg +version: 0.1.0 diff --git a/k8s/helm/webshoppingagg/templates/NOTES.txt b/k8s/helm/webshoppingagg/templates/NOTES.txt new file mode 100644 index 000000000..f55946f36 --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/NOTES.txt @@ -0,0 +1,8 @@ +eShop Web Shopping Aggregator installed. +---------------------------------------- + +This API is not directly exposed outside cluster. If need to access it use: + +export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "webshoppingagg.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +echo "Visit http://127.0.0.1:8080 to use your application" +kubectl port-forward $POD_NAME 8080:80 diff --git a/k8s/helm/webshoppingagg/templates/_helpers.tpl b/k8s/helm/webshoppingagg/templates/_helpers.tpl new file mode 100644 index 000000000..f13dc791d --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webshoppingagg.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webshoppingagg.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webshoppingagg.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webshoppingagg/templates/_names.tpl b/k8s/helm/webshoppingagg/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webshoppingagg/templates/configmap.yaml b/k8s/helm/webshoppingagg/templates/configmap.yaml new file mode 100644 index 000000000..b4d3da041 --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{- $name := include "webshoppingagg.fullname" . -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webshoppingagg.name" . }} + chart: {{ template "webshoppingagg.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + webshoppingagg__keystore: {{ .Values.inf.redis.keystore.constr }} + internalurls__basket: http://{{ .Values.app.svc.basket }} + internalurls__catalog: http://{{ .Values.app.svc.catalog }} + internalurls__identity: http://{{ .Values.app.svc.identity }} + internalurls__ordering: http://{{ .Values.app.svc.ordering }} + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc diff --git a/k8s/helm/webshoppingagg/templates/deployment.yaml b/k8s/helm/webshoppingagg/templates/deployment.yaml new file mode 100644 index 000000000..8007c74c8 --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- $name := include "webshoppingagg.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webshoppingagg.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webshoppingagg.name" . }} + chart: {{ template "webshoppingagg.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webshoppingagg.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webshoppingagg.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{ if .Values.probes -}} + {{- if .Values.probes.liveness -}} + livenessProbe: + httpGet: + port: {{ .Values.probes.liveness.port }} + path: {{ .Values.probes.liveness.path }} + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds }} + {{- end -}} + {{- end -}} + {{- if .Values.probes -}} + {{- if .Values.probes.readiness }} + readinessProbe: + httpGet: + port: {{ .Values.probes.readiness.port }} + path: {{ .Values.probes.readiness.path }} + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds }} + timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} + {{- end -}} + {{- end }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webshoppingagg/templates/service.yaml b/k8s/helm/webshoppingagg/templates/service.yaml new file mode 100644 index 000000000..8f0cb8bd5 --- /dev/null +++ b/k8s/helm/webshoppingagg/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.webshoppingagg }} + labels: + app: {{ template "webshoppingagg.name" . }} + chart: {{ template "webshoppingagg.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webshoppingagg.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webshoppingagg/values.yaml b/k8s/helm/webshoppingagg/values.yaml new file mode 100644 index 000000000..f4f2c5fd7 --- /dev/null +++ b/k8s/helm/webshoppingagg/values.yaml @@ -0,0 +1,79 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webshoppingagg + +image: + repository: eshop/webshoppingagg + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: urls__basket + key: internalurls__basket + - name: urls__catalog + key: internalurls__catalog + - name: urls__orders + key: internalurls__ordering + - name: urls__identity + key: internalurls__identity + - name: CatalogUrlHC + key: internalurls__catalog__hc + - name: BasketUrlHC + key: internalurls__basket__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: OrderingUrlHC + key: internalurls__ordering__hc + - name: MarketingUrlHC + key: internalurls__marketing__hc + - name: PaymentUrlHC + key: internalurls__payment__hc + - name: LocationUrlHC + key: internalurls__location__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: ASPNETCORE_URLS + value: http://0.0.0.0:80 + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + value: 'True' +probes: + liveness: + path: /liveness + initialDelaySeconds: 10 + periodSeconds: 15 + port: 80 + readiness: + path: /hc + timeoutSeconds: 5 + initialDelaySeconds: 90 + periodSeconds: 60 + port: 80 + diff --git a/k8s/helm/webspa/.helmignore b/k8s/helm/webspa/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webspa/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webspa/Chart.yaml b/k8s/helm/webspa/Chart.yaml new file mode 100644 index 000000000..c16616489 --- /dev/null +++ b/k8s/helm/webspa/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webspa +version: 0.1.0 diff --git a/k8s/helm/webspa/templates/NOTES.txt b/k8s/helm/webspa/templates/NOTES.txt new file mode 100644 index 000000000..c8e1622db --- /dev/null +++ b/k8s/helm/webspa/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop WebSPA installed +---------------------- \ No newline at end of file diff --git a/k8s/helm/webspa/templates/_helpers.tpl b/k8s/helm/webspa/templates/_helpers.tpl new file mode 100644 index 000000000..585f9f001 --- /dev/null +++ b/k8s/helm/webspa/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webspa.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webspa.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webspa.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webspa/templates/_names.tpl b/k8s/helm/webspa/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/webspa/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webspa/templates/configmap.yaml b/k8s/helm/webspa/templates/configmap.yaml new file mode 100644 index 000000000..7d4651a31 --- /dev/null +++ b/k8s/helm/webspa/templates/configmap.yaml @@ -0,0 +1,29 @@ +{{- $name := include "webspa.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} +{{- $webmarketingapigw := include "url-of" (list .Values.app.ingress.entries.webmarketingapigw .) -}} +{{- $spa := include "url-of" (list .Values.app.ingress.entries.spa .) -}} +{{- $mongo := include "mongo-name" . -}} + + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webspa.name" . }} + chart: {{ template "webspa.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + webspa__keystore: {{ .Values.inf.redis.keystore.constr }} + internalurls__apigwws: http://{{ .Values.app.svc.webshoppingapigw }} + internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc + urls__apigwws: http://{{ $webshoppingapigw }} + urls__spa: http://{{ $spa }} + urls__IdentityUrl: http://{{ $identity }} + urls__apigwwm: http://{{ $webmarketingapigw }} \ No newline at end of file diff --git a/k8s/helm/webspa/templates/deployment.yaml b/k8s/helm/webspa/templates/deployment.yaml new file mode 100644 index 000000000..62af2d8b1 --- /dev/null +++ b/k8s/helm/webspa/templates/deployment.yaml @@ -0,0 +1,71 @@ +{{- $name := include "webspa.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webspa.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webspa.name" . }} + chart: {{ template "webspa.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webspa.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webspa.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webspa/templates/ingress.yaml b/k8s/helm/webspa/templates/ingress.yaml new file mode 100644 index 000000000..85419f8e7 --- /dev/null +++ b/k8s/helm/webspa/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "webspa.fullname" . }} + labels: + app: {{ template "webspa.name" . }} + chart: {{ template "webspa.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.spa }} + servicePort: http +{{- end }} diff --git a/k8s/helm/webspa/templates/service.yaml b/k8s/helm/webspa/templates/service.yaml new file mode 100644 index 000000000..2eab5d02e --- /dev/null +++ b/k8s/helm/webspa/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.spa }} + labels: + app: {{ template "webspa.name" . }} + chart: {{ template "webspa.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webspa.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webspa/values.yaml b/k8s/helm/webspa/values.yaml new file mode 100644 index 000000000..056b58a0d --- /dev/null +++ b/k8s/helm/webspa/values.yaml @@ -0,0 +1,65 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: / + +image: + repository: eshop/webspa + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: {} + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: UseLoadTest + key: all_EnableLoadTest + - name: DPConnectionString + key: webspa__keystore + - name: PurchaseUrl + key: urls__apigwws + - name: CallBackUrl + key: urls__spa + - name: IdentityUrl + key: urls__IdentityUrl + - name: MarketingUrl + key: urls__apigwwm + - name: PurchaseUrlHC + key: internalurls__apigwws__hc + - name: IdentityUrlHC + key: internalurls__identity__hc + - name: MarketingUrlHC + key: internalurls__apigwwm__hc + - name: SignalrHubUrl + key: urls__apigwws + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: ASPNETCORE_URLS + value: http://0.0.0.0:80 + - name: OrchestratorType + value: 'K8S' + - name: IsClusterEnv + value: 'True' + diff --git a/k8s/helm/webstatus/.helmignore b/k8s/helm/webstatus/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/k8s/helm/webstatus/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/k8s/helm/webstatus/Chart.yaml b/k8s/helm/webstatus/Chart.yaml new file mode 100644 index 000000000..9ee2783f4 --- /dev/null +++ b/k8s/helm/webstatus/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: webstatus +version: 0.1.0 diff --git a/k8s/helm/webstatus/templates/NOTES.txt b/k8s/helm/webstatus/templates/NOTES.txt new file mode 100644 index 000000000..5d9d4570d --- /dev/null +++ b/k8s/helm/webstatus/templates/NOTES.txt @@ -0,0 +1,2 @@ +eShop WebStatus installed. +-------------------------- \ No newline at end of file diff --git a/k8s/helm/webstatus/templates/_helpers.tpl b/k8s/helm/webstatus/templates/_helpers.tpl new file mode 100644 index 000000000..65b290af7 --- /dev/null +++ b/k8s/helm/webstatus/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "webstatus.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "webstatus.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "webstatus.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/k8s/helm/webstatus/templates/_names.tpl b/k8s/helm/webstatus/templates/_names.tpl new file mode 100644 index 000000000..d44859fea --- /dev/null +++ b/k8s/helm/webstatus/templates/_names.tpl @@ -0,0 +1,52 @@ +{{- define "suffix-name" -}} +{{- if .Values.app.name -}} +{{- .Values.app.name -}} +{{- else -}} +{{- .Release.Name -}} +{{- end -}} +{{- end -}} + +{{- define "sql-name" -}} +{{- if .Values.inf.sql.host -}} +{{- .Values.inf.sql.host -}} +{{- else -}} +{{- printf "%s" "sql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "mongo-name" -}} +{{- if .Values.inf.mongo.host -}} +{{- .Values.inf.mongo.host -}} +{{- else -}} +{{- printf "%s" "nosql-data" -}} +{{- end -}} +{{- end -}} + +{{- define "url-of" -}} +{{- $name := first .}} +{{- $ctx := last .}} +{{- if eq $name "" -}} +{{- $ctx.Values.inf.k8s.dns -}} +{{- else -}} +{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just / */}} +{{- end -}} +{{- end -}} + + + +{{- define "pathBase" -}} +{{- if .Values.inf.k8s.suffix -}} +{{- $suffix := include "suffix-name" . -}} +{{- printf "%s-%s" .Values.pathBase $suffix -}} +{{- else -}} +{{- .Values.pathBase -}} +{{- end -}} +{{- end -}} + +{{- define "fqdn-image" -}} +{{- if .Values.inf.registry -}} +{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}} +{{- else -}} +{{- .Values.image.repository -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webstatus/templates/configmap.yaml b/k8s/helm/webstatus/templates/configmap.yaml new file mode 100644 index 000000000..3f32d7adc --- /dev/null +++ b/k8s/helm/webstatus/templates/configmap.yaml @@ -0,0 +1,55 @@ +{{- $name := include "webstatus.fullname" . -}} +{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} +{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} +{{- $mvc := include "url-of" (list .Values.app.ingress.entries.mvc .) -}} +{{- $mongo := include "mongo-name" . -}} + + +apiVersion: v1 +kind: ConfigMap +metadata: + name: "cfg-{{ $name }}" + labels: + app: {{ template "webstatus.name" . }} + chart: {{ template "webstatus.chart" .}} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + all__InstrumentationKey: {{ .Values.inf.appinsights.key }} + all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" + all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" + webstatus__keystore: {{ .Values.inf.redis.keystore.constr }} + name__mvc__hc: WebMVC HTTP Check + internalurls__mvc__hc: http://{{ .Values.app.svc.mvc }}/hc + name__spa__hc: WebSPA HTTP Check + internalurls__spa__hc: http://{{ .Values.app.svc.spa }}/hc + name__apigwws__hc: Web Shopping API GW HTTP Check + internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc + name__apigwwm__hc: Web Marketing API GW HTTP Check + internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc + name__apigwms__hc: Mobile Shopping API GW HTTP Check + internalurls__apigwms__hc: http://{{ .Values.app.svc.mobileshoppingapigw }}/hc + name__apigwmm__hc: Mobile Marketing API GW HTTP Check + internalurls__apigwmm__hc: http://{{ .Values.app.svc.mobilemarketingapigw }}/hc + name__apigwwsagg__hc: Web Shopping Aggregator GW HTTP Check + internalurls__apigwwsagg__hc: http://{{ .Values.app.svc.webshoppingagg }}/hc + name__apigwmsagg__hc: Mobile Shopping Aggregator HTTP Check + internalurls__apigwmsagg__hc: http://{{ .Values.app.svc.mobileshoppingagg }}/hc + name__ordering__hc: Ordering HTTP Check + internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc + name__orderingbackground__hc: Ordering HTTP Background Check + internalurls__orderingbackground__hc: http://{{ .Values.app.svc.orderingbackgroundtasks }}/hc + name__basket__hc: Basket HTTP Check + internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc + name__catalog__hc: Catalog HTTP Check + internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc + name__identity__hc: Identity HTTP Check + internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc + name__marketing__hc: Marketing HTTP Check + internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc + name__locations__hc: Locations HTTP Check + internalurls__locations__hc: http://{{ .Values.app.svc.locations }}/hc + name__payment__hc: Payment HTTP Check + internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc + name__signalrhub__hc: Ordering SignalR Hub HTTP Check + internalurls__signalrhub__hc: http://{{ .Values.app.svc.orderingsignalrhub }}/hc diff --git a/k8s/helm/webstatus/templates/deployment.yaml b/k8s/helm/webstatus/templates/deployment.yaml new file mode 100644 index 000000000..6f96f81fb --- /dev/null +++ b/k8s/helm/webstatus/templates/deployment.yaml @@ -0,0 +1,71 @@ +{{- $name := include "webstatus.fullname" . -}} +{{- $cfgname := printf "%s-%s" "cfg" $name -}} +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "webstatus.fullname" . }} + labels: + ufo: {{ $cfgname}} + app: {{ template "webstatus.name" . }} + chart: {{ template "webstatus.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "webstatus.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "webstatus.name" . }} + release: {{ .Release.Name }} + spec: + {{ if .Values.inf.registry -}} + imagePullSecrets: + - name: {{ .Values.inf.registry.secretName }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: PATH_BASE + value: {{ include "pathBase" . }} + - name: k8sname + value: {{ .Values.clusterName }} + {{- if .Values.env.values -}} + {{- range .Values.env.values }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end -}} + {{- end -}} + {{- if .Values.env.configmap -}} + {{- range .Values.env.configmap }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ $cfgname }} + key: {{ .key }} + {{- end -}} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + diff --git a/k8s/helm/webstatus/templates/ingress.yaml b/k8s/helm/webstatus/templates/ingress.yaml new file mode 100644 index 000000000..1ab4e5e22 --- /dev/null +++ b/k8s/helm/webstatus/templates/ingress.yaml @@ -0,0 +1,34 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "webstatus.fullname" . -}} +{{- $ingressPath := include "pathBase" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "webstatus.fullname" . }} + labels: + app: {{ template "webstatus.name" . }} + chart: {{ template "webstatus.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + - {{ .Values.inf.k8s.dns }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + - host: {{ .Values.inf.k8s.dns }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ .Values.app.svc.status }} + servicePort: http +{{- end }} diff --git a/k8s/helm/webstatus/templates/service.yaml b/k8s/helm/webstatus/templates/service.yaml new file mode 100644 index 000000000..37fff50c6 --- /dev/null +++ b/k8s/helm/webstatus/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.svc.status }} + labels: + app: {{ template "webstatus.name" . }} + chart: {{ template "webstatus.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "webstatus.name" . }} + release: {{ .Release.Name }} diff --git a/k8s/helm/webstatus/values.yaml b/k8s/helm/webstatus/values.yaml new file mode 100644 index 000000000..88cae5d7f --- /dev/null +++ b/k8s/helm/webstatus/values.yaml @@ -0,0 +1,110 @@ +replicaCount: 1 +clusterName: eshop-aks +pathBase: /webstatus + +image: + repository: eshop/webstatus + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + annotations: { + + } + tls: [] + +resources: {} + + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# env defines the environment variables that will be declared in the pod +env: + urls: + # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). + configmap: + - name: ApplicationInsights__InstrumentationKey + key: all__InstrumentationKey + - name: HealthChecks-UI__HealthChecks__0__Name + key: name__mvc__hc + - name: HealthChecks-UI__HealthChecks__0__Uri + key: internalurls__mvc__hc + - name: HealthChecks-UI__HealthChecks__1__Name + key: name__spa__hc + - name: HealthChecks-UI__HealthChecks__1__Uri + key: internalurls__spa__hc + - name: HealthChecks-UI__HealthChecks__2__Name + key: name__apigwws__hc + - name: HealthChecks-UI__HealthChecks__2__Uri + key: internalurls__apigwws__hc + - name: HealthChecks-UI__HealthChecks__3__Name + key: name__apigwwm__hc + - name: HealthChecks-UI__HealthChecks__3__Uri + key: internalurls__apigwwm__hc + - name: HealthChecks-UI__HealthChecks__4__Name + key: name__apigwms__hc + - name: HealthChecks-UI__HealthChecks__4__Uri + key: internalurls__apigwms__hc + - name: HealthChecks-UI__HealthChecks__5__Name + key: name__apigwmm__hc + - name: HealthChecks-UI__HealthChecks__5__Uri + key: internalurls__apigwmm__hc + - name: HealthChecks-UI__HealthChecks__6__Name + key: name__apigwwsagg__hc + - name: HealthChecks-UI__HealthChecks__6__Uri + key: internalurls__apigwwsagg__hc + - name: HealthChecks-UI__HealthChecks__7__Name + key: name__apigwmsagg__hc + - name: HealthChecks-UI__HealthChecks__7__Uri + key: internalurls__apigwmsagg__hc + - name: HealthChecks-UI__HealthChecks__8__Name + key: name__ordering__hc + - name: HealthChecks-UI__HealthChecks__8__Uri + key: internalurls__ordering__hc + - name: HealthChecks-UI__HealthChecks__9__Name + key: name__orderingbackground__hc + - name: HealthChecks-UI__HealthChecks__9__Uri + key: internalurls__orderingbackground__hc + - name: HealthChecks-UI__HealthChecks__10__Name + key: name__signalrhub__hc + - name: HealthChecks-UI__HealthChecks__10__Uri + key: internalurls__signalrhub__hc + - name: HealthChecks-UI__HealthChecks__11__Name + key: name__basket__hc + - name: HealthChecks-UI__HealthChecks__11__Uri + key: internalurls__basket__hc + - name: HealthChecks-UI__HealthChecks__12__Name + key: name__catalog__hc + - name: HealthChecks-UI__HealthChecks__12__Uri + key: internalurls__catalog__hc + - name: HealthChecks-UI__HealthChecks__13__Name + key: name__identity__hc + - name: HealthChecks-UI__HealthChecks__13__Uri + key: internalurls__identity__hc + - name: HealthChecks-UI__HealthChecks__14__Name + key: name__marketing__hc + - name: HealthChecks-UI__HealthChecks__14__Uri + key: internalurls__marketing__hc + - name: HealthChecks-UI__HealthChecks__15__Name + key: name__locations__hc + - name: HealthChecks-UI__HealthChecks__15__Uri + key: internalurls__locations__hc + - name: HealthChecks-UI__HealthChecks__16__Name + key: name__payment__hc + - name: HealthChecks-UI__HealthChecks__16__Uri + key: internalurls__payment__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) + values: + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: OrchestratorType + value: 'K8S' diff --git a/k8s/nginx-ingress/azure/service.yaml b/k8s/nginx-ingress/azure/service.yaml deleted file mode 100644 index 8d2f71505..000000000 --- a/k8s/nginx-ingress/azure/service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: ingress-nginx - namespace: ingress-nginx - labels: - app: ingress-nginx -spec: - externalTrafficPolicy: Local - type: LoadBalancer - selector: - app: ingress-nginx - ports: - - name: http - port: 80 - targetPort: http - - name: https - port: 443 - targetPort: https diff --git a/k8s/nginx-ingress/cloud-generic.yaml b/k8s/nginx-ingress/cloud-generic.yaml new file mode 100644 index 000000000..945441ab8 --- /dev/null +++ b/k8s/nginx-ingress/cloud-generic.yaml @@ -0,0 +1,21 @@ +kind: Service +apiVersion: v1 +metadata: + name: ingress-nginx + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +spec: + externalTrafficPolicy: Local + type: LoadBalancer + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + ports: + - name: http + port: 80 + targetPort: http + - name: https + port: 443 + targetPort: https \ No newline at end of file diff --git a/k8s/nginx-ingress/cm.yaml b/k8s/nginx-ingress/cm.yaml new file mode 100644 index 000000000..7818fd15b Binary files /dev/null and b/k8s/nginx-ingress/cm.yaml differ diff --git a/k8s/nginx-ingress/configmap.yaml b/k8s/nginx-ingress/configmap.yaml deleted file mode 100644 index 6703fc38e..000000000 --- a/k8s/nginx-ingress/configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: nginx-configuration - namespace: ingress-nginx - labels: - app: ingress-nginx -data: - ssl-redirect: "false" - proxy-buffer-size: "128k" - proxy-buffers: "4 256k" diff --git a/k8s/nginx-ingress/default-backend.yaml b/k8s/nginx-ingress/default-backend.yaml deleted file mode 100644 index 64f6f58ad..000000000 --- a/k8s/nginx-ingress/default-backend.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: default-http-backend - labels: - app: default-http-backend - namespace: ingress-nginx -spec: - replicas: 1 - template: - metadata: - labels: - app: default-http-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-http-backend - # Any image is permissable as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: gcr.io/google_containers/defaultbackend:1.4 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi ---- - -apiVersion: v1 -kind: Service -metadata: - name: default-http-backend - namespace: ingress-nginx - labels: - app: default-http-backend -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: default-http-backend diff --git a/k8s/nginx-ingress/local-dockerk8s/identityapi-cm-fix.yaml b/k8s/nginx-ingress/local-dockerk8s/identityapi-cm-fix.yaml new file mode 100644 index 000000000..3a3fcf5a5 --- /dev/null +++ b/k8s/nginx-ingress/local-dockerk8s/identityapi-cm-fix.yaml @@ -0,0 +1,3 @@ +data: + mvc_e: http://10.0.75.1/webmvc + \ No newline at end of file diff --git a/k8s/nginx-ingress/local-dockerk8s/mvc-cm-fix.yaml b/k8s/nginx-ingress/local-dockerk8s/mvc-cm-fix.yaml new file mode 100644 index 000000000..1475deec1 --- /dev/null +++ b/k8s/nginx-ingress/local-dockerk8s/mvc-cm-fix.yaml @@ -0,0 +1,3 @@ +data: + urls__IdentityUrl: http://10.0.75.1/identity + urls__mvc: http://10.0.75.1/webmvc diff --git a/k8s/nginx-ingress/local-dockerk8s/mvc-fix.yaml b/k8s/nginx-ingress/local-dockerk8s/mvc-fix.yaml new file mode 100644 index 000000000..b9ecd4cba --- /dev/null +++ b/k8s/nginx-ingress/local-dockerk8s/mvc-fix.yaml @@ -0,0 +1,39 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/ssl-redirect: "false" + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "false" + labels: + app: webmvc + name: eshop-webmvc-loopback + namespace: default +spec: + rules: + - http: + paths: + - backend: + serviceName: webmvc + servicePort: http + path: /webmvc +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/ssl-redirect: "false" + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "false" + labels: + app: identity-api + name: eshop-identity-api-loopback + namespace: default +spec: + rules: + - http: + paths: + - backend: + serviceName: identity + servicePort: http + path: /identity \ No newline at end of file diff --git a/k8s/nginx-ingress/mandatory.yaml b/k8s/nginx-ingress/mandatory.yaml new file mode 100644 index 000000000..56b1cc3b5 --- /dev/null +++ b/k8s/nginx-ingress/mandatory.yaml @@ -0,0 +1,238 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ingress-nginx + +--- + +kind: ConfigMap +apiVersion: v1 +metadata: + name: nginx-configuration + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nginx-ingress-serviceaccount + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: nginx-ingress-clusterrole + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +rules: + - apiGroups: + - "" + resources: + - configmaps + - endpoints + - nodes + - pods + - secrets + verbs: + - list + - watch + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch + - apiGroups: + - "extensions" + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - apiGroups: + - "extensions" + resources: + - ingresses/status + verbs: + - update + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: nginx-ingress-role + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +rules: + - apiGroups: + - "" + resources: + - configmaps + - pods + - secrets + - namespaces + verbs: + - get + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + # Defaults to "-" + # Here: "-" + # This has to be adapted if you change either parameter + # when launching the nginx-ingress-controller. + - "ingress-controller-leader-nginx" + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: nginx-ingress-role-nisa-binding + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: nginx-ingress-role +subjects: + - kind: ServiceAccount + name: nginx-ingress-serviceaccount + namespace: ingress-nginx + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: nginx-ingress-clusterrole-nisa-binding + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nginx-ingress-clusterrole +subjects: + - kind: ServiceAccount + name: nginx-ingress-serviceaccount + namespace: ingress-nginx + +--- + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-ingress-controller + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + template: + metadata: + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + annotations: + prometheus.io/port: "10254" + prometheus.io/scrape: "true" + spec: + serviceAccountName: nginx-ingress-serviceaccount + containers: + - name: nginx-ingress-controller + image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0 + args: + - /nginx-ingress-controller + - --configmap=$(POD_NAMESPACE)/nginx-configuration + - --publish-service=$(POD_NAMESPACE)/ingress-nginx + - --annotations-prefix=nginx.ingress.kubernetes.io + securityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + # www-data -> 33 + runAsUser: 33 + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - name: http + containerPort: 80 + - name: https + containerPort: 443 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 diff --git a/k8s/nginx-ingress/namespace.yaml b/k8s/nginx-ingress/namespace.yaml deleted file mode 100644 index 6878f0be8..000000000 --- a/k8s/nginx-ingress/namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: ingress-nginx diff --git a/k8s/nginx-ingress/patch-service-without-rbac.yaml b/k8s/nginx-ingress/patch-service-without-rbac.yaml deleted file mode 100644 index 919efc389..000000000 --- a/k8s/nginx-ingress/patch-service-without-rbac.yaml +++ /dev/null @@ -1,40 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-ingress-controller - namespace: ingress-nginx -spec: - replicas: 1 - selector: - matchLabels: - app: ingress-nginx - template: - metadata: - labels: - app: ingress-nginx - spec: - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --configmap=$(POD_NAMESPACE)/nginx-configuration - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - - --publish-service=$(POD_NAMESPACE)/ingress-nginx - - --annotations-prefix=nginx.ingress.kubernetes.io - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - name: http - containerPort: 80 - - name: https - containerPort: 443 diff --git a/k8s/nginx-ingress/publish-service-patch.yaml b/k8s/nginx-ingress/publish-service-patch.yaml deleted file mode 100644 index f8f52f772..000000000 --- a/k8s/nginx-ingress/publish-service-patch.yaml +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - 'op': 'add', - 'path': '/spec/template/spec/containers/0/args/-', - 'value': '--publish-service=$(POD_NAMESPACE)/ingress-nginx' - } -] diff --git a/k8s/nginx-ingress/service-nodeport.yaml b/k8s/nginx-ingress/service-nodeport.yaml new file mode 100644 index 000000000..dd82ed3ed --- /dev/null +++ b/k8s/nginx-ingress/service-nodeport.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + name: ingress-nginx + namespace: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +spec: + type: NodePort + ports: + - name: http + port: 80 + targetPort: 80 + protocol: TCP + - name: https + port: 443 + targetPort: 443 + protocol: TCP + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx diff --git a/k8s/nginx-ingress/tcp-services-configmap.yaml b/k8s/nginx-ingress/tcp-services-configmap.yaml deleted file mode 100644 index a963085d3..000000000 --- a/k8s/nginx-ingress/tcp-services-configmap.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: tcp-services - namespace: ingress-nginx diff --git a/k8s/nginx-ingress/udp-services-configmap.yaml b/k8s/nginx-ingress/udp-services-configmap.yaml deleted file mode 100644 index 1870931a2..000000000 --- a/k8s/nginx-ingress/udp-services-configmap.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: udp-services - namespace: ingress-nginx diff --git a/k8s/nginx-ingress/without-rbac.yaml b/k8s/nginx-ingress/without-rbac.yaml deleted file mode 100644 index 1c46b73eb..000000000 --- a/k8s/nginx-ingress/without-rbac.yaml +++ /dev/null @@ -1,61 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-ingress-controller - namespace: ingress-nginx -spec: - replicas: 1 - selector: - matchLabels: - app: ingress-nginx - template: - metadata: - labels: - app: ingress-nginx - annotations: - prometheus.io/port: '10254' - prometheus.io/scrape: 'true' - spec: - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --configmap=$(POD_NAMESPACE)/nginx-configuration - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - - --annotations-prefix=nginx.ingress.kubernetes.io - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - name: http - containerPort: 80 - - name: https - containerPort: 443 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 diff --git a/run-docker-compose-build.ps1 b/run-docker-compose-build.ps1 new file mode 100644 index 000000000..7d99ee0e7 --- /dev/null +++ b/run-docker-compose-build.ps1 @@ -0,0 +1,14 @@ +$startTime = $(Get-Date) + +docker-compose build + +$elapsedTime = $(Get-Date) - $startTime + +$elapsedTime + +# "Beep" from: http://jeffwouters.nl/index.php/2012/03/get-your-geek-on-with-powershell-and-some-music/ +[console]::beep(900,400) +[console]::beep(1000,400) +[console]::beep(800,400) +[console]::beep(400,400) +[console]::beep(600,1600) diff --git a/src/ApiGateways/ApiGw-Base/Dockerfile b/src/ApiGateways/ApiGw-Base/Dockerfile index 7f0cf43a6..eb94675b9 100644 --- a/src/ApiGateways/ApiGw-Base/Dockerfile +++ b/src/ApiGateways/ApiGw-Base/Dockerfile @@ -1,13 +1,12 @@ -FROM microsoft/aspnetcore:2.0 AS base +FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base WORKDIR /app EXPOSE 80 -FROM microsoft/aspnetcore-build:2.0 AS build +FROM microsoft/dotnet:2.2.100-sdk AS build WORKDIR /src -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -RUN dotnet restore src/ApiGateways/ApiGw-Base/ COPY . . WORKDIR /src/src/ApiGateways/ApiGw-Base/ +RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet build -c Release -o /app FROM build AS publish diff --git a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj b/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj index d72d014b4..eb88972c0 100644 --- a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj +++ b/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj @@ -1,16 +1,17 @@ - + - netcoreapp2.0 + netcoreapp2.2 - + + + + + + + + - - - - - - diff --git a/src/ApiGateways/ApiGw-Base/Program.cs b/src/ApiGateways/ApiGw-Base/Program.cs index effd5684e..bcf1c8d60 100644 --- a/src/ApiGateways/ApiGw-Base/Program.cs +++ b/src/ApiGateways/ApiGw-Base/Program.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; +using Serilog; namespace OcelotApiGw { @@ -23,7 +24,20 @@ namespace OcelotApiGw IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args); builder.ConfigureServices(s => s.AddSingleton(builder)) .ConfigureAppConfiguration(ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json"))) - .UseStartup(); + .UseStartup() + .ConfigureLogging((hostingContext, loggingbuilder) => + { + loggingbuilder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + loggingbuilder.AddConsole(); + loggingbuilder.AddDebug(); + }) + .UseSerilog((builderContext, config) => + { + config + .MinimumLevel.Information() + .Enrich.FromLogContext() + .WriteTo.Console(); + }); IWebHost host = builder.Build(); return host; } diff --git a/src/ApiGateways/ApiGw-Base/Startup.cs b/src/ApiGateways/ApiGw-Base/Startup.cs index f6a36b59e..585c26471 100644 --- a/src/ApiGateways/ApiGw-Base/Startup.cs +++ b/src/ApiGateways/ApiGw-Base/Startup.cs @@ -1,22 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using CacheManager.Core; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Ocelot.DependencyInjection; using Ocelot.Middleware; +using System; +using HealthChecks.UI.Client; +using Microsoft.Extensions.Diagnostics.HealthChecks; namespace OcelotApiGw { public class Startup { - private readonly IConfiguration _cfg; public Startup(IConfiguration configuration) @@ -29,12 +26,23 @@ namespace OcelotApiGw var identityUrl = _cfg.GetValue("IdentityUrl"); var authenticationProviderKey = "IdentityApiKey"; + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddUrlGroup(new Uri(_cfg["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) + .AddUrlGroup(new Uri(_cfg["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) + .AddUrlGroup(new Uri(_cfg["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) + .AddUrlGroup(new Uri(_cfg["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) + .AddUrlGroup(new Uri(_cfg["MarketingUrlHC"]), name: "marketingapi-check", tags: new string[] { "marketingapi" }) + .AddUrlGroup(new Uri(_cfg["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }) + .AddUrlGroup(new Uri(_cfg["LocationUrlHC"]), name: "locationapi-check", tags: new string[] { "locationapi" }); + services.AddCors(options => { options.AddPolicy("CorsPolicy", - builder => builder.AllowAnyOrigin() + builder => builder .AllowAnyMethod() .AllowAnyHeader() + .SetIsOriginAllowed((host) => true) .AllowCredentials()); }); @@ -68,9 +76,10 @@ namespace OcelotApiGw services.AddOcelot(_cfg); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var pathBase = _cfg["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) { app.UsePathBase(pathBase); @@ -81,7 +90,16 @@ namespace OcelotApiGw app.UseDeveloperExceptionPage(); } - loggerFactory.AddConsole(_cfg.GetSection("Logging")); + app.UseHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.UseHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); app.UseCors("CorsPolicy"); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs index 702c805fb..978b1858c 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class BasketController : Controller + [ApiController] + public class BasketController : ControllerBase { private readonly ICatalogService _catalog; private readonly IBasketService _basket; + public BasketController(ICatalogService catalogService, IBasketService basketService) { _catalog = catalogService; @@ -23,22 +26,24 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers [HttpPost] [HttpPut] - public async Task UpdateAllBasket([FromBody] UpdateBasketRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) { - if (data.Items == null || !data.Items.Any()) { return BadRequest("Need to pass at least one basket line"); } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BuyerId); + var currentBasket = await _basket.GetByIdAsync(data.BuyerId); + if (currentBasket == null) { currentBasket = new BasketData(data.BuyerId); } - var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId)); + var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); var newBasket = new BasketData(data.BuyerId); foreach (var bitem in data.Items) @@ -60,13 +65,16 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers }); } - await _basket.Update(newBasket); - return Ok(newBasket); + await _basket.UpdateAsync(newBasket); + + return newBasket; } [HttpPut] [Route("items")] - public async Task UpdateQuantities([FromBody] UpdateBasketItemsRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) { if (!data.Updates.Any()) { @@ -74,7 +82,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BasketId); + var currentBasket = await _basket.GetByIdAsync(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -84,21 +92,26 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers foreach (var update in data.Updates) { var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); + if (basketItem == null) { return BadRequest($"Basket item with id {update.BasketItemId} not found"); } + basketItem.Quantity = update.NewQty; } // Save the updated basket - await _basket.Update(currentBasket); - return Ok(currentBasket); + await _basket.UpdateAsync(currentBasket); + + return currentBasket; } [HttpPost] [Route("items")] - public async Task AddBasketItem([FromBody] AddBasketItemRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task AddBasketItemAsync([FromBody] AddBasketItemRequest data) { if (data == null || data.Quantity == 0) { @@ -106,12 +119,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Step 1: Get the item from catalog - var item = await _catalog.GetCatalogItem(data.CatalogItemId); + var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); + var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); // Step 3: Merge current status with new product currentBasket.Items.Add(new BasketDataItem() { @@ -124,8 +137,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers }); // Step 4: Update basket - await _basket.Update(currentBasket); - + await _basket.UpdateAsync(currentBasket); return Ok(); } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs index 4c18d25ae..a4b33c6cb 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -1,19 +1,20 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; -using System; -using System.Collections.Generic; -using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class OrderController : Controller + [ApiController] + public class OrderController : ControllerBase { private readonly IBasketService _basketService; private readonly IOrderApiClient _orderClient; + public OrderController(IBasketService basketService, IOrderApiClient orderClient) { _basketService = basketService; @@ -22,21 +23,23 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers [Route("draft/{basketId}")] [HttpGet] - public async Task GetOrderDraft(string basketId) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] + public async Task> GetOrderDraftAsync(string basketId) { if (string.IsNullOrEmpty(basketId)) { return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetById(basketId); + var basket = await _basketService.GetByIdAsync(basketId); + if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); - return Ok(orderDraft); + return await _orderClient.GetOrderDraftFromBasketAsync(basket); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile index 273743cee..be89c315f 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile @@ -1,12 +1,12 @@ -FROM microsoft/aspnetcore:2.0.5 AS base +FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base WORKDIR /app EXPOSE 80 -FROM microsoft/aspnetcore-build:2.0 AS build +FROM microsoft/dotnet:2.2.100-sdk AS build WORKDIR /src COPY . . -RUN dotnet restore -nowarn:msb3202,nu1503 WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator +RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet build --no-restore -c Release -o /app FROM build AS publish diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs new file mode 100644 index 000000000..967a8c826 --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure +{ + public class HttpClientAuthorizationDelegatingHandler + : DelegatingHandler + { + private readonly IHttpContextAccessor _httpContextAccesor; + + public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) + { + _httpContextAccesor = httpContextAccesor; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var authorizationHeader = _httpContextAccesor.HttpContext + .Request.Headers["Authorization"]; + + if (!string.IsNullOrEmpty(authorizationHeader)) + { + request.Headers.Add("Authorization", new List() { authorizationHeader }); + } + + var token = await GetToken(); + + if (token != null) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + } + + return await base.SendAsync(request, cancellationToken); + } + + async Task GetToken() + { + const string ACCESS_TOKEN = "access_token"; + + return await _httpContextAccesor.HttpContext + .GetTokenAsync(ACCESS_TOKEN); + } + } +} diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj index bd6d73950..1e9508843 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj @@ -1,7 +1,7 @@ - + - netcoreapp2.0 + netcoreapp2.2 Mobile.Shopping.HttpAggregator Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator ..\..\..\docker-compose.dcproj @@ -12,16 +12,15 @@ - - - - - - - - - - + + + + + + + + + diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs index 0c88fcd7d..fc21a70a4 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Serilog; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { @@ -31,6 +32,13 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator }); }) .UseStartup() + .UseSerilog((builderContext, config) => + { + config + .MinimumLevel.Information() + .Enrich.FromLogContext() + .WriteTo.Console(); + }) .Build(); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs index b00fbb52c..5186fe361 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs @@ -1,53 +1,41 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public class BasketService : IBasketService { - private readonly IHttpClient _apiClient; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - private readonly IHttpContextAccessor _httpContextAccessor; - public BasketService(IHttpClient httpClient, IHttpContextAccessor httpContextAccessor, ILogger logger, IOptionsSnapshot config) + public BasketService(HttpClient httpClient, ILogger logger, IOptions config) { - _apiClient = httpClient; + _httpClient = httpClient; _logger = logger; _urls = config.Value; - _httpContextAccessor = httpContextAccessor; } - public async Task GetById(string id) + public async Task GetByIdAsync(string id) { - var token = await GetUserTokenAsync(); - var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id), token); + var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); + var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; + return basket; } - public async Task Update(BasketData currentBasket) + public async Task UpdateAsync(BasketData currentBasket) { - var token = await GetUserTokenAsync(); - var data = await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), currentBasket, token); - int i = 0; - } + var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); - async Task GetUserTokenAsync() - { - var context = _httpContextAccessor.HttpContext; - return await context.GetTokenAsync("access_token"); + var data = await _httpClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs index d37b67679..69bca2b39 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -1,43 +1,41 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public class CatalogService : ICatalogService { - - private readonly IHttpClient _apiClient; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - public CatalogService(IHttpClient httpClient, ILogger logger, IOptionsSnapshot config) + public CatalogService(HttpClient httpClient, ILogger logger, IOptions config) { - _apiClient = httpClient; + _httpClient = httpClient; _logger = logger; _urls = config.Value; } - public async Task GetCatalogItem(int id) + public async Task GetCatalogItemAsync(int id) { - var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); - var item = JsonConvert.DeserializeObject(data); - return item; + var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); + var catalogItem = JsonConvert.DeserializeObject(stringContent); + + return catalogItem; } - public async Task> GetCatalogItems(IEnumerable ids) + public async Task> GetCatalogItemsAsync(IEnumerable ids) { - var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); - var item = JsonConvert.DeserializeObject(data); - return item; + var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); + var catalogItems = JsonConvert.DeserializeObject(stringContent); + return catalogItems; } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs index 6fd6871c1..ad49e1adb 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -1,15 +1,13 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetById(string id); - Task Update(BasketData currentBasket); + Task GetByIdAsync(string id); + + Task UpdateAsync(BasketData currentBasket); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs index d7e605bfa..832dfc740 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs @@ -1,14 +1,13 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface ICatalogService { - Task GetCatalogItem(int id); - Task> GetCatalogItems(IEnumerable ids); + Task GetCatalogItemAsync(int id); + + Task> GetCatalogItemsAsync(IEnumerable ids); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs index 30ac013b9..1abe545bd 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs @@ -1,13 +1,10 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface IOrderApiClient { - Task GetOrderDraftFromBasket(BasketData basket); + Task GetOrderDraftFromBasketAsync(BasketData basket); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs index 2659e11cc..da39abbff 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs @@ -1,37 +1,37 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public class OrderApiClient : IOrderApiClient { - - private readonly IHttpClient _apiClient; + private readonly HttpClient _apiClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - public OrderApiClient(IHttpClient httpClient, ILogger logger, IOptionsSnapshot config) + public OrderApiClient(HttpClient httpClient, ILogger logger, IOptions config) { _apiClient = httpClient; _logger = logger; _urls = config.Value; } - public async Task GetOrderDraftFromBasket(BasketData basket) + public async Task GetOrderDraftFromBasketAsync(BasketData basket) { - var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); - var response = await _apiClient.PostAsync(url, basket); + var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); + var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + var response = await _apiClient.PostAsync(uri, content); + response.EnsureSuccessStatusCode(); - var jsonResponse = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(jsonResponse); + + var ordersDraftResponse = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(ordersDraftResponse); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs index 73b736519..924b5b1aa 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs @@ -1,21 +1,25 @@ using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Threading.Tasks; +using System.Net.Http; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using Polly.Extensions.Http; using Swashbuckle.AspNetCore.Swagger; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { @@ -31,16 +35,80 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) + .AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) + .AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) + .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) + .AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapi-check", tags: new string[] { "marketingapi" }) + .AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }) + .AddUrlGroup(new Uri(Configuration["LocationUrlHC"]), name: "locationapi-check", tags: new string[] { "locationapi" }); + + services.AddCustomMvc(Configuration) + .AddCustomAuthentication(Configuration) + .AddHttpServices(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + var pathBase = Configuration["PATH_BASE"]; + + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); + app.UsePathBase(pathBase); + } + + app.UseHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.UseHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + + app.UseCors("CorsPolicy"); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseAuthentication(); + app.UseHttpsRedirection(); + app.UseMvc(); + + app.UseSwagger().UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); + + c.OAuthClientId("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui"); + c.OAuthClientSecret(string.Empty); + c.OAuthRealm(string.Empty); + c.OAuthAppName("Purchase BFF Swagger UI"); + }); + } + } + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) + { services.AddOptions(); - services.Configure(Configuration.GetSection("urls")); + services.Configure(configuration.GetSection("urls")); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(options => { @@ -57,8 +125,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { Type = "oauth2", Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", + AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", + TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", Scopes = new Dictionary() { { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } @@ -71,21 +139,27 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator services.AddCors(options => { options.AddPolicy("CorsPolicy", - builder => builder.AllowAnyOrigin() + builder => builder .AllowAnyMethod() .AllowAnyHeader() + .SetIsOriginAllowed((host) => true) .AllowCredentials()); }); - + return services; + } + public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) + { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - var identityUrl = Configuration.GetValue("urls:identity"); + var identityUrl = configuration.GetValue("urls:identity"); + services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }).AddJwtBearer(options => + }) + .AddJwtBearer(options => { options.Authority = identityUrl; options.RequireHttpsMetadata = false; @@ -94,45 +168,52 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { OnAuthenticationFailed = async ctx => { - int i = 0; }, OnTokenValidated = async ctx => { - int i = 0; } }; }); + + return services; } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public static IServiceCollection AddHttpServices(this IServiceCollection services) { + //register delegating handlers + services.AddTransient(); + services.AddSingleton(); - var pathBase = Configuration["PATH_BASE"]; - if (!string.IsNullOrEmpty(pathBase)) - { - loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); - app.UsePathBase(pathBase); - } - - app.UseCors("CorsPolicy"); + //register http services + services.AddHttpClient() + .AddHttpMessageHandler() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + services.AddHttpClient() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - app.UseAuthentication(); + services.AddHttpClient() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - app.UseMvc(); - - app.UseSwagger().UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); - c.ConfigureOAuth2("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); - }); + return services; + } + private static IAsyncPolicy GetRetryPolicy() + { + return HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) + .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + } + private static IAsyncPolicy GetCircuitBreakerPolicy() + { + return HttpPolicyExtensions + .HandleTransientHttpError() + .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs index bfef55726..6745ffa02 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class BasketController : Controller + [ApiController] + public class BasketController : ControllerBase { private readonly ICatalogService _catalog; private readonly IBasketService _basket; + public BasketController(ICatalogService catalogService, IBasketService basketService) { _catalog = catalogService; @@ -23,22 +26,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers [HttpPost] [HttpPut] - public async Task UpdateAllBasket([FromBody] UpdateBasketRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) { - if (data.Items == null || !data.Items.Any()) { return BadRequest("Need to pass at least one basket line"); } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BuyerId); + var currentBasket = await _basket.GetByIdAsync(data.BuyerId); if (currentBasket == null) { currentBasket = new BasketData(data.BuyerId); } - var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId)); + var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); var newBasket = new BasketData(data.BuyerId); foreach (var bitem in data.Items) @@ -60,13 +64,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers }); } - await _basket.Update(newBasket); - return Ok(newBasket); + await _basket.UpdateAsync(newBasket); + + return newBasket; } [HttpPut] [Route("items")] - public async Task UpdateQuantities([FromBody] UpdateBasketItemsRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) { if (!data.Updates.Any()) { @@ -74,7 +81,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BasketId); + var currentBasket = await _basket.GetByIdAsync(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -92,13 +99,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Save the updated basket - await _basket.Update(currentBasket); - return Ok(currentBasket); + await _basket.UpdateAsync(currentBasket); + + return currentBasket; } [HttpPost] [Route("items")] - public async Task AddBasketItem([FromBody] AddBasketItemRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task AddBasketItemAsync([FromBody] AddBasketItemRequest data) { if (data == null || data.Quantity == 0) { @@ -106,12 +116,12 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Step 1: Get the item from catalog - var item = await _catalog.GetCatalogItem(data.CatalogItemId); + var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); + var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); // Step 3: Merge current status with new product currentBasket.Items.Add(new BasketDataItem() { @@ -124,8 +134,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers }); // Step 4: Update basket - await _basket.Update(currentBasket); - + await _basket.UpdateAsync(currentBasket); return Ok(); } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs index fd108ffb8..de3e4cc55 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -1,16 +1,19 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class OrderController : Controller + [ApiController] + public class OrderController : ControllerBase { private readonly IBasketService _basketService; private readonly IOrderApiClient _orderClient; @@ -22,21 +25,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers [Route("draft/{basketId}")] [HttpGet] - public async Task GetOrderDraft(string basketId) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] + public async Task> GetOrderDraftAsync(string basketId) { if (string.IsNullOrEmpty(basketId)) { return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetById(basketId); + var basket = await _basketService.GetByIdAsync(basketId); + if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); - return Ok(orderDraft); + return await _orderClient.GetOrderDraftFromBasketAsync(basket); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile index ce6f1b155..236d3705a 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile @@ -1,12 +1,12 @@ -FROM microsoft/aspnetcore:2.0.5 AS base +FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base WORKDIR /app EXPOSE 80 -FROM microsoft/aspnetcore-build:2.0 AS build +FROM microsoft/dotnet:2.2.100-sdk AS build WORKDIR /src COPY . . -RUN dotnet restore -nowarn:msb3202,nu1503 WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator +RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet build --no-restore -c Release -o /app FROM build AS publish diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs new file mode 100644 index 000000000..4e54829f8 --- /dev/null +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure +{ + public class HttpClientAuthorizationDelegatingHandler + : DelegatingHandler + { + private readonly IHttpContextAccessor _httpContextAccesor; + + public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) + { + _httpContextAccesor = httpContextAccesor; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var authorizationHeader = _httpContextAccesor.HttpContext + .Request.Headers["Authorization"]; + + if (!string.IsNullOrEmpty(authorizationHeader)) + { + request.Headers.Add("Authorization", new List() { authorizationHeader }); + } + + var token = await GetToken(); + + if (token != null) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + } + + return await base.SendAsync(request, cancellationToken); + } + + async Task GetToken() + { + const string ACCESS_TOKEN = "access_token"; + + return await _httpContextAccesor.HttpContext + .GetTokenAsync(ACCESS_TOKEN); + } + } +} diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs index c865a8b3b..4bbac21e6 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Serilog; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { @@ -31,6 +32,13 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator }); }) .UseStartup() + .UseSerilog((builderContext, config) => + { + config + .MinimumLevel.Information() + .Enrich.FromLogContext() + .WriteTo.Console(); + }) .Build(); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs index 5ca89a408..d0fb5c008 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs @@ -1,53 +1,39 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class BasketService : IBasketService { - - private readonly IHttpClient _apiClient; + private readonly HttpClient _apiClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - private readonly IHttpContextAccessor _httpContextAccessor; - public BasketService(IHttpClient httpClient, IHttpContextAccessor httpContextAccessor, ILogger logger, IOptionsSnapshot config) + public BasketService(HttpClient httpClient,ILogger logger, IOptions config) { _apiClient = httpClient; _logger = logger; _urls = config.Value; - _httpContextAccessor = httpContextAccessor; } - public async Task GetById(string id) + public async Task GetByIdAsync(string id) { - var token = await GetUserTokenAsync(); - var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id), token); + var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; + return basket; } - public async Task Update(BasketData currentBasket) + public async Task UpdateAsync(BasketData currentBasket) { - var token = await GetUserTokenAsync(); - var data = await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), currentBasket, token); - int i = 0; - } + var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); - async Task GetUserTokenAsync() - { - var context = _httpContextAccessor.HttpContext; - return await context.GetTokenAsync("access_token"); + await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs index 46d895f68..159e56d85 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -1,43 +1,39 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class CatalogService : ICatalogService { - - private readonly IHttpClient _apiClient; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - public CatalogService(IHttpClient httpClient, ILogger logger, IOptionsSnapshot config) + public CatalogService(HttpClient httpClient, ILogger logger, IOptions config) { - _apiClient = httpClient; + _httpClient = httpClient; _logger = logger; _urls = config.Value; } - public async Task GetCatalogItem(int id) + public async Task GetCatalogItemAsync(int id) { - var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); - var item = JsonConvert.DeserializeObject(data); - return item; + var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); + + return JsonConvert.DeserializeObject(stringContent); } - public async Task> GetCatalogItems(IEnumerable ids) + public async Task> GetCatalogItemsAsync(IEnumerable ids) { - var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); - var item = JsonConvert.DeserializeObject(data); - return item; + var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); + return JsonConvert.DeserializeObject(stringContent); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs index f59c31965..046ef753d 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -1,15 +1,12 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetById(string id); - Task Update(BasketData currentBasket); + Task GetByIdAsync(string id); + Task UpdateAsync(BasketData currentBasket); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs index 7d192f3cc..9f86b84f9 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs @@ -1,14 +1,13 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface ICatalogService { - Task GetCatalogItem(int id); - Task> GetCatalogItems(IEnumerable ids); + Task GetCatalogItemAsync(int id); + + Task> GetCatalogItemsAsync(IEnumerable ids); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs index c97eccbbd..0e972833c 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs @@ -1,13 +1,10 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface IOrderApiClient { - Task GetOrderDraftFromBasket(BasketData basket); + Task GetOrderDraftFromBasketAsync(BasketData basket); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs index 220e9afa9..a26028d69 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs @@ -1,37 +1,37 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; -using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; +using System.Net.Http; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class OrderApiClient : IOrderApiClient { - - private readonly IHttpClient _apiClient; + private readonly HttpClient _apiClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; - public OrderApiClient(IHttpClient httpClient, ILogger logger, IOptionsSnapshot config) + public OrderApiClient(HttpClient httpClient, ILogger logger, IOptions config) { _apiClient = httpClient; _logger = logger; _urls = config.Value; } - public async Task GetOrderDraftFromBasket(BasketData basket) + public async Task GetOrderDraftFromBasketAsync(BasketData basket) { var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); - var response = await _apiClient.PostAsync(url, basket); + var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + var response = await _apiClient.PostAsync(url, content); + response.EnsureSuccessStatusCode(); - var jsonResponse = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(jsonResponse); + + var ordersDraftResponse = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(ordersDraftResponse); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs index 17f9f90e6..6d3da29b7 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs @@ -1,21 +1,26 @@ -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using Polly.Extensions.Http; +using Polly.Timeout; using Swashbuckle.AspNetCore.Swagger; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Net.Http; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { @@ -31,16 +36,106 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) + .AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) + .AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) + .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) + .AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapi-check", tags: new string[] { "marketingapi" }) + .AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }) + .AddUrlGroup(new Uri(Configuration["LocationUrlHC"]), name: "locationapi-check", tags: new string[] { "locationapi" }); + + services.AddCustomMvc(Configuration) + .AddCustomAuthentication(Configuration) + .AddApplicationServices(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); + app.UsePathBase(pathBase); + } + app.UseHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.UseHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + + app.UseCors("CorsPolicy"); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseAuthentication(); + app.UseHttpsRedirection(); + app.UseMvc(); + + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); + //c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); + }); + } + } + + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) + { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + var identityUrl = configuration.GetValue("urls:identity"); + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + + }).AddJwtBearer(options => + { + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "webshoppingagg"; + options.Events = new JwtBearerEvents() + { + OnAuthenticationFailed = async ctx => + { + int i = 0; + }, + OnTokenValidated = async ctx => + { + int i = 0; + } + }; + }); + + return services; + } + + public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) + { services.AddOptions(); - services.Configure(Configuration.GetSection("urls")); + services.Configure(configuration.GetSection("urls")); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(options => { @@ -57,8 +152,8 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { Type = "oauth2", Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", + AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", + TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", Scopes = new Dictionary() { { "webshoppingagg", "Shopping Aggregator for Web Clients" } @@ -71,68 +166,55 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator services.AddCors(options => { options.AddPolicy("CorsPolicy", - builder => builder.AllowAnyOrigin() + builder => builder + .SetIsOriginAllowed((host) => true) .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); - - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - var identityUrl = Configuration.GetValue("urls:identity"); - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }).AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "webshoppingagg"; - options.Events = new JwtBearerEvents() - { - OnAuthenticationFailed = async ctx => - { - int i = 0; - }, - OnTokenValidated = async ctx => - { - int i = 0; - } - }; - }); + return services; } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public static IServiceCollection AddApplicationServices(this IServiceCollection services) { + //register delegating handlers + services.AddTransient(); + services.AddSingleton(); - var pathBase = Configuration["PATH_BASE"]; - if (!string.IsNullOrEmpty(pathBase)) - { - loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); - app.UsePathBase(pathBase); - } + //register http services + + services.AddHttpClient() + .AddHttpMessageHandler() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - app.UseCors("CorsPolicy"); + services.AddHttpClient() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + services.AddHttpClient() + .AddHttpMessageHandler() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); - app.UseAuthentication(); - app.UseMvc(); + return services; + } - app.UseSwagger().UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); - c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); - }); + static IAsyncPolicy GetRetryPolicy() + { + return HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) + .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + } + static IAsyncPolicy GetCircuitBreakerPolicy() + { + return HttpPolicyExtensions + .HandleTransientHttpError() + .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj index 0b6dbf44b..a15e101d3 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj @@ -1,7 +1,7 @@ - + - netcoreapp2.0 + netcoreapp2.2 Web.Shopping.HttpAggregator Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator ..\..\..\docker-compose.dcproj @@ -12,16 +12,14 @@ - - - - - - - - - - + + + + + + + + diff --git a/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationEventHandler.cs b/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationEventHandler.cs index 0b5b793ee..72e1ed2cd 100644 --- a/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationEventHandler.cs +++ b/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationEventHandler.cs @@ -6,11 +6,11 @@ using System.Threading.Tasks; namespace EventBus.Tests { - public class TestIntegrationOtherEventHandler : IIntegrationEventHandler + public class TestIntegrationEventHandler : IIntegrationEventHandler { public bool Handled { get; private set; } - public TestIntegrationOtherEventHandler() + public TestIntegrationEventHandler() { Handled = false; } diff --git a/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationOtherEventHandler.cs b/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationOtherEventHandler.cs index 72e1ed2cd..0b5b793ee 100644 --- a/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationOtherEventHandler.cs +++ b/src/BuildingBlocks/EventBus/EventBus.Tests/TestIntegrationOtherEventHandler.cs @@ -6,11 +6,11 @@ using System.Threading.Tasks; namespace EventBus.Tests { - public class TestIntegrationEventHandler : IIntegrationEventHandler + public class TestIntegrationOtherEventHandler : IIntegrationEventHandler { public bool Handled { get; private set; } - public TestIntegrationEventHandler() + public TestIntegrationOtherEventHandler() { Handled = false; } diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index b219dcfa1..9704f6ff5 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -6,7 +6,7 @@ - + \ No newline at end of file diff --git a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs index e01a7aaa8..ef09911fe 100644 --- a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs +++ b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs @@ -1,4 +1,5 @@ using System; +using Newtonsoft.Json; namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events { @@ -10,7 +11,17 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events CreationDate = DateTime.UtcNow; } - public Guid Id { get; } - public DateTime CreationDate { get; } + [JsonConstructor] + public IntegrationEvent(Guid id, DateTime createDate) + { + Id = id; + CreationDate = createDate; + } + + [JsonProperty] + public Guid Id { get; private set; } + + [JsonProperty] + public DateTime CreationDate { get; private set; } } } diff --git a/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs b/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs new file mode 100644 index 000000000..de5a2cb79 --- /dev/null +++ b/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions +{ + public static class GenericTypeExtensions + { + public static string GetGenericTypeName(this Type type) + { + var typeName = string.Empty; + + if (type.IsGenericType) + { + var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray()); + typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>"; + } + else + { + typeName = type.Name; + } + + return typeName; + } + + public static string GetGenericTypeName(this object @object) + { + return @object.GetType().GetGenericTypeName(); + } + } +} diff --git a/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs b/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs index 88be8cf96..e789081f3 100644 --- a/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs +++ b/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs @@ -1,10 +1,8 @@ -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; -using System; +using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus { @@ -37,8 +35,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus where TH : IIntegrationEventHandler { var eventName = GetEventKey(); + DoAddSubscription(typeof(TH), eventName, isDynamic: false); - _eventTypes.Add(typeof(T)); + + if (!_eventTypes.Contains(typeof(T))) + { + _eventTypes.Add(typeof(T)); + } } private void DoAddSubscription(Type handlerType, string eventName, bool isDynamic) diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs similarity index 91% rename from src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs rename to src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs index 2e0555e61..93e5b2917 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs @@ -72,7 +72,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ .Or() .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => { - _logger.LogWarning(ex.ToString()); + _logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message); } ); @@ -88,7 +88,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ _connection.CallbackException += OnCallbackException; _connection.ConnectionBlocked += OnConnectionBlocked; - _logger.LogInformation($"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events"); + _logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName); return true; } diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs index 49a417635..ac379d50a 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs @@ -2,6 +2,7 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -76,7 +77,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ .Or() .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => { - _logger.LogWarning(ex.ToString()); + _logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message); }); using (var channel = _persistentConnection.CreateModel()) @@ -107,6 +108,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ public void SubscribeDynamic(string eventName) where TH : IDynamicIntegrationEventHandler { + _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + DoInternalSubscription(eventName); _subsManager.AddDynamicSubscription(eventName); } @@ -117,6 +120,9 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ { var eventName = _subsManager.GetEventKey(); DoInternalSubscription(eventName); + + _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + _subsManager.AddSubscription(); } @@ -140,9 +146,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ } public void Unsubscribe() - where TH : IIntegrationEventHandler where T : IntegrationEvent + where TH : IIntegrationEventHandler { + var eventName = _subsManager.GetEventKey(); + + _logger.LogInformation("Unsubscribing from event {EventName}", eventName); + _subsManager.RemoveSubscription(); } @@ -215,16 +225,18 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ foreach (var subscription in subscriptions) { if (subscription.IsDynamic) - { + { var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; + if (handler == null) continue; dynamic eventData = JObject.Parse(message); await handler.Handle(eventData); } else { + var handler = scope.ResolveOptional(subscription.HandlerType); + if (handler == null) continue; var eventType = _subsManager.GetEventTypeByName(eventName); var integrationEvent = JsonConvert.DeserializeObject(message, eventType); - var handler = scope.ResolveOptional(subscription.HandlerType); var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); } diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj index d6c9fc8e2..62373d1b3 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj @@ -7,12 +7,12 @@ - - - - + + + + - + diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersistentConnection.cs similarity index 100% rename from src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersisterConnection.cs rename to src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersistentConnection.cs diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs index 446fcd7b7..cd2dc557f 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs @@ -22,15 +22,15 @@ private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus"; private const string INTEGRATION_EVENT_SUFIX = "IntegrationEvent"; - public EventBusServiceBus(IServiceBusPersisterConnection serviceBusPersisterConnection, + public EventBusServiceBus(IServiceBusPersisterConnection serviceBusPersisterConnection, ILogger logger, IEventBusSubscriptionsManager subsManager, string subscriptionClientName, ILifetimeScope autofac) { _serviceBusPersisterConnection = serviceBusPersisterConnection; - _logger = logger; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); - _subscriptionClient = new SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder, + _subscriptionClient = new SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder, subscriptionClientName); _autofac = autofac; @@ -61,6 +61,8 @@ public void SubscribeDynamic(string eventName) where TH : IDynamicIntegrationEventHandler { + _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, nameof(TH)); + _subsManager.AddDynamicSubscription(eventName); } @@ -68,7 +70,7 @@ where T : IntegrationEvent where TH : IIntegrationEventHandler { - var eventName = typeof(T).Name.Replace(INTEGRATION_EVENT_SUFIX, ""); + var eventName = typeof(T).Name.Replace(INTEGRATION_EVENT_SUFIX, ""); var containsKey = _subsManager.HasSubscriptionsForEvent(); if (!containsKey) @@ -81,12 +83,14 @@ Name = eventName }).GetAwaiter().GetResult(); } - catch(ServiceBusException) + catch (ServiceBusException) { - _logger.LogInformation($"The messaging entity {eventName} already exists."); + _logger.LogWarning("The messaging entity {eventName} already exists.", eventName); } } + _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, nameof(TH)); + _subsManager.AddSubscription(); } @@ -105,15 +109,19 @@ } catch (MessagingEntityNotFoundException) { - _logger.LogInformation($"The messaging entity {eventName} Could not be found."); + _logger.LogWarning("The messaging entity {eventName} Could not be found.", eventName); } + _logger.LogInformation("Unsubscribing from event {EventName}", eventName); + _subsManager.RemoveSubscription(); } public void UnsubscribeDynamic(string eventName) where TH : IDynamicIntegrationEventHandler { + _logger.LogInformation("Unsubscribing from dynamic event {EventName}", eventName); + _subsManager.RemoveDynamicSubscription(eventName); } @@ -129,27 +137,29 @@ { var eventName = $"{message.Label}{INTEGRATION_EVENT_SUFIX}"; var messageData = Encoding.UTF8.GetString(message.Body); - await ProcessEvent(eventName, messageData); - + // Complete the message so that it is not received again. - await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken); + if (await ProcessEvent(eventName, messageData)) + { + await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken); + } }, - new MessageHandlerOptions(ExceptionReceivedHandler) { MaxConcurrentCalls = 10, AutoComplete = false }); + new MessageHandlerOptions(ExceptionReceivedHandler) { MaxConcurrentCalls = 10, AutoComplete = false }); } private Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs) { - Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}."); + var ex = exceptionReceivedEventArgs.Exception; var context = exceptionReceivedEventArgs.ExceptionReceivedContext; - Console.WriteLine("Exception context for troubleshooting:"); - Console.WriteLine($"- Endpoint: {context.Endpoint}"); - Console.WriteLine($"- Entity Path: {context.EntityPath}"); - Console.WriteLine($"- Executing Action: {context.Action}"); + + _logger.LogError(ex, "ERROR handling message: {ExceptionMessage} - Context: {@ExceptionContext}", ex.Message, context); + return Task.CompletedTask; } - private async Task ProcessEvent(string eventName, string message) + private async Task ProcessEvent(string eventName, string message) { + var processed = false; if (_subsManager.HasSubscriptionsForEvent(eventName)) { using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) @@ -160,20 +170,24 @@ if (subscription.IsDynamic) { var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; + if (handler == null) continue; dynamic eventData = JObject.Parse(message); await handler.Handle(eventData); } else { + var handler = scope.ResolveOptional(subscription.HandlerType); + if (handler == null) continue; var eventType = _subsManager.GetEventTypeByName(eventName); var integrationEvent = JsonConvert.DeserializeObject(message, eventType); - var handler = scope.ResolveOptional(subscription.HandlerType); var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); } } } + processed = true; } + return processed; } private void RemoveDefaultRule() @@ -187,8 +201,8 @@ } catch (MessagingEntityNotFoundException) { - _logger.LogInformation($"The messaging entity { RuleDescription.DefaultRuleName } Could not be found."); + _logger.LogWarning("The messaging entity {DefaultRuleName} Could not be found.", RuleDescription.DefaultRuleName); } } } -} +} \ No newline at end of file diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj index 8e76a02db..3de07e329 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/EventStateEnum.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/EventStateEnum.cs index 3efb78e74..079cf7d7e 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/EventStateEnum.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/EventStateEnum.cs @@ -7,7 +7,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF public enum EventStateEnum { NotPublished = 0, - Published = 1, - PublishedFailed = 2 + InProgress = 1, + Published = 2, + PublishedFailed = 3 } } diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj index d4f380a14..ef3463cca 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj @@ -6,18 +6,12 @@ - - - - - - - - - - - - + + + + + + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs index 3cab9e500..e5c3bc9ad 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Text; using Newtonsoft.Json; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using System.Linq; +using System.ComponentModel.DataAnnotations.Schema; +using System.Reflection; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF { @@ -11,7 +14,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF private IntegrationEventLogEntry() { } public IntegrationEventLogEntry(IntegrationEvent @event) { - EventId = @event.Id; + EventId = @event.Id; CreationTime = @event.CreationDate; EventTypeName = @event.GetType().FullName; Content = JsonConvert.SerializeObject(@event); @@ -20,9 +23,19 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF } public Guid EventId { get; private set; } public string EventTypeName { get; private set; } + [NotMapped] + public string EventTypeShortName => EventTypeName.Split('.')?.Last(); + [NotMapped] + public IntegrationEvent IntegrationEvent { get; private set; } public EventStateEnum State { get; set; } public int TimesSent { get; set; } public DateTime CreationTime { get; private set; } public string Content { get; private set; } + + public IntegrationEventLogEntry DeserializeJsonContent(Type type) + { + IntegrationEvent = JsonConvert.DeserializeObject(Content, type) as IntegrationEvent; + return this; + } } } diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IIntegrationEventLogService.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IIntegrationEventLogService.cs index ed1f74616..6167d8ae8 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IIntegrationEventLogService.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IIntegrationEventLogService.cs @@ -9,7 +9,10 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi { public interface IIntegrationEventLogService { + Task> RetrieveEventLogsPendingToPublishAsync(); Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction); - Task MarkEventAsPublishedAsync(IntegrationEvent @event); + Task MarkEventAsPublishedAsync(Guid eventId); + Task MarkEventAsInProgressAsync(Guid eventId); + Task MarkEventAsFailedAsync(Guid eventId); } } diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs index 5ac8bb862..2712c5e1c 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs @@ -1,12 +1,15 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Newtonsoft.Json; +using System; +using System.Collections; +using System.Collections.Generic; using System.Data.Common; using System.Linq; +using System.Reflection; using System.Threading.Tasks; -using System; -using Microsoft.EntityFrameworkCore.Diagnostics; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services { @@ -14,37 +17,69 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi { private readonly IntegrationEventLogContext _integrationEventLogContext; private readonly DbConnection _dbConnection; + private readonly List _eventTypes; public IntegrationEventLogService(DbConnection dbConnection) { - _dbConnection = dbConnection?? throw new ArgumentNullException("dbConnection"); + _dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection)); _integrationEventLogContext = new IntegrationEventLogContext( new DbContextOptionsBuilder() .UseSqlServer(_dbConnection) .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)) .Options); + + _eventTypes = Assembly.Load(Assembly.GetEntryAssembly().FullName) + .GetTypes() + .Where(t => t.Name.EndsWith(nameof(IntegrationEvent))) + .ToList(); + } + + public async Task> RetrieveEventLogsPendingToPublishAsync() + { + return await _integrationEventLogContext.IntegrationEventLogs + .Where(e => e.State == EventStateEnum.NotPublished) + .OrderBy(o => o.CreationTime) + .Select(e => e.DeserializeJsonContent(_eventTypes.Find(t=> t.Name == e.EventTypeShortName))) + .ToListAsync(); } public Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction) { - if(transaction == null) + if (transaction == null) { - throw new ArgumentNullException("transaction", $"A {typeof(DbTransaction).FullName} is required as a pre-requisite to save the event."); + throw new ArgumentNullException(nameof(transaction), $"A {typeof(DbTransaction).FullName} is required as a pre-requisite to save the event."); } - + var eventLogEntry = new IntegrationEventLogEntry(@event); - + _integrationEventLogContext.Database.UseTransaction(transaction); _integrationEventLogContext.IntegrationEventLogs.Add(eventLogEntry); return _integrationEventLogContext.SaveChangesAsync(); } - public Task MarkEventAsPublishedAsync(IntegrationEvent @event) + public Task MarkEventAsPublishedAsync(Guid eventId) { - var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == @event.Id); - eventLogEntry.TimesSent++; - eventLogEntry.State = EventStateEnum.Published; + return UpdateEventStatus(eventId, EventStateEnum.Published); + } + + public Task MarkEventAsInProgressAsync(Guid eventId) + { + return UpdateEventStatus(eventId, EventStateEnum.InProgress); + } + + public Task MarkEventAsFailedAsync(Guid eventId) + { + return UpdateEventStatus(eventId, EventStateEnum.PublishedFailed); + } + + private Task UpdateEventStatus(Guid eventId, EventStateEnum status) + { + var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == eventId); + eventLogEntry.State = status; + + if(status == EventStateEnum.InProgress) + eventLogEntry.TimesSent++; _integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry); diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckMiddleware.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckMiddleware.cs deleted file mode 100644 index f8e68c957..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckMiddleware.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.HealthChecks; -using Newtonsoft.Json; - -namespace Microsoft.AspNetCore.HealthChecks -{ - public class HealthCheckMiddleware - { - private readonly RequestDelegate _next; - private readonly string _path; - private readonly int? _port; - private readonly IHealthCheckService _service; - private readonly TimeSpan _timeout; - - public HealthCheckMiddleware(RequestDelegate next, IHealthCheckService service, int port, TimeSpan timeout) - { - _port = port; - _service = service; - _next = next; - _timeout = timeout; - } - - public HealthCheckMiddleware(RequestDelegate next, IHealthCheckService service, string path, TimeSpan timeout) - { - _path = path; - _service = service; - _next = next; - _timeout = timeout; - } - - public async Task Invoke(HttpContext context) - { - if (IsHealthCheckRequest(context)) - { - var timeoutTokenSource = new CancellationTokenSource(_timeout); - var result = await _service.CheckHealthAsync(timeoutTokenSource.Token); - var status = result.CheckStatus; - - if (status != CheckStatus.Healthy) - context.Response.StatusCode = 503; - - context.Response.Headers.Add("content-type", "application/json"); - await context.Response.WriteAsync(JsonConvert.SerializeObject(new { status = status.ToString() })); - return; - } - else - { - await _next.Invoke(context); - } - } - - private bool IsHealthCheckRequest(HttpContext context) - { - if (_port.HasValue) - { - var connInfo = context.Features.Get(); - if (connInfo.LocalPort == _port) - return true; - } - - if (context.Request.Path == _path) - { - return true; - } - - return false; - } - } -} \ No newline at end of file diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckStartupFilter.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckStartupFilter.cs deleted file mode 100644 index cac4b1188..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckStartupFilter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; - -namespace Microsoft.AspNetCore.HealthChecks -{ - public class HealthCheckStartupFilter : IStartupFilter - { - private string _path; - private int? _port; - private TimeSpan _timeout; - - public HealthCheckStartupFilter(int port, TimeSpan timeout) - { - _port = port; - _timeout = timeout; - } - - public HealthCheckStartupFilter(string path, TimeSpan timeout) - { - _path = path; - _timeout = timeout; - } - - public Action Configure(Action next) - { - return app => - { - if (_port.HasValue) - { - app.UseMiddleware(_port, _timeout); - } - else - { - app.UseMiddleware(_path, _timeout); - } - - next(app); - }; - } - } -} \ No newline at end of file diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostBuilderExtension.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostBuilderExtension.cs deleted file mode 100644 index 467293137..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostBuilderExtension.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.HealthChecks; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Hosting -{ - public static class HealthCheckWebHostBuilderExtension - { - public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(10); - - public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, int port) - => UseHealthChecks(builder, port, DefaultTimeout); - - public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, int port, TimeSpan timeout) - { - Guard.ArgumentValid(port > 0 && port < 65536, nameof(port), "Port must be a value between 1 and 65535."); - Guard.ArgumentValid(timeout > TimeSpan.Zero, nameof(timeout), "Health check timeout must be a positive time span."); - - builder.ConfigureServices(services => - { - var existingUrl = builder.GetSetting(WebHostDefaults.ServerUrlsKey); - builder.UseSetting(WebHostDefaults.ServerUrlsKey, $"{existingUrl};http://localhost:{port}"); - - services.AddSingleton(new HealthCheckStartupFilter(port, timeout)); - }); - return builder; - } - - public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, string path) - => UseHealthChecks(builder, path, DefaultTimeout); - - public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, string path, TimeSpan timeout) - { - Guard.ArgumentNotNull(nameof(path), path); - // REVIEW: Is there a better URL path validator somewhere? - Guard.ArgumentValid(!path.Contains("?"), nameof(path), "Path cannot contain query string values."); - Guard.ArgumentValid(path.StartsWith("/"), nameof(path), "Path should start with '/'."); - Guard.ArgumentValid(timeout > TimeSpan.Zero, nameof(timeout), "Health check timeout must be a positive time span."); - - builder.ConfigureServices(services => services.AddSingleton(new HealthCheckStartupFilter(path, timeout))); - return builder; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostExtensions.cs deleted file mode 100644 index 67448ff17..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/HealthCheckWebHostExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.HealthChecks; - -namespace Microsoft.AspNetCore.Hosting -{ - public static class HealthCheckWebHostExtensions - { - private const int DEFAULT_TIMEOUT_SECONDS = 300; - - public static void RunWhenHealthy(this IWebHost webHost) - { - webHost.RunWhenHealthy(TimeSpan.FromSeconds(DEFAULT_TIMEOUT_SECONDS)); - } - - public static void RunWhenHealthy(this IWebHost webHost, TimeSpan timeout) - { - var healthChecks = webHost.Services.GetService(typeof(IHealthCheckService)) as IHealthCheckService; - - var loops = 0; - do - { - var checkResult = healthChecks.CheckHealthAsync().Result; - if (checkResult.CheckStatus == CheckStatus.Healthy) - { - webHost.Run(); - break; - } - - System.Threading.Thread.Sleep(1000); - loops++; - - } while (loops < timeout.TotalSeconds); - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj deleted file mode 100644 index 5018e198c..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/AzureHealthCheckBuilderExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/AzureHealthCheckBuilderExtensions.cs deleted file mode 100644 index 5a06a3ba2..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/AzureHealthCheckBuilderExtensions.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Auth; - -namespace Microsoft.Extensions.HealthChecks -{ - // REVIEW: Do we want these to continue to use default parameters? - // REVIEW: What are the appropriate guards for these functions? - - public static class AzureHealthCheckBuilderExtensions - { - public static HealthCheckBuilder AddAzureBlobStorageCheck(this HealthCheckBuilder builder, string accountName, string accountKey, string containerName = null, TimeSpan? cacheDuration = null) - { - var credentials = new StorageCredentials(accountName, accountKey); - var storageAccount = new CloudStorageAccount(credentials, true); - return AddAzureBlobStorageCheck(builder, storageAccount, containerName, cacheDuration); - } - - public static HealthCheckBuilder AddAzureBlobStorageCheck(HealthCheckBuilder builder, CloudStorageAccount storageAccount, string containerName = null, TimeSpan? cacheDuration = null) - { - builder.AddCheck($"AzureBlobStorageCheck {storageAccount.BlobStorageUri} {containerName}", async () => - { - bool result; - try - { - var blobClient = storageAccount.CreateCloudBlobClient(); - - var properties = await blobClient.GetServicePropertiesAsync().ConfigureAwait(false); - - if (!String.IsNullOrWhiteSpace(containerName)) - { - var container = blobClient.GetContainerReference(containerName); - - result = await container.ExistsAsync(); - } - - result = true; - } - catch (Exception) - { - result = false; - } - - return result - ? HealthCheckResult.Healthy($"AzureBlobStorage {storageAccount.BlobStorageUri} is available") - : HealthCheckResult.Unhealthy($"AzureBlobStorage {storageAccount.BlobStorageUri} is unavailable"); - }, cacheDuration ?? builder.DefaultCacheDuration); - - return builder; - } - - public static HealthCheckBuilder AddAzureTableStorageCheck(this HealthCheckBuilder builder, string accountName, string accountKey, string tableName = null, TimeSpan? cacheDuration = null) - { - var credentials = new StorageCredentials(accountName, accountKey); - var storageAccount = new CloudStorageAccount(credentials, true); - return AddAzureTableStorageCheck(builder, storageAccount, tableName, cacheDuration); - } - - public static HealthCheckBuilder AddAzureTableStorageCheck(HealthCheckBuilder builder, CloudStorageAccount storageAccount, string tableName = null, TimeSpan? cacheDuration = null) - { - builder.AddCheck($"AzureTableStorageCheck {storageAccount.TableStorageUri} {tableName}", async () => - { - bool result; - try - { - var tableClient = storageAccount.CreateCloudTableClient(); - - var properties = await tableClient.GetServicePropertiesAsync().ConfigureAwait(false); - - if (!String.IsNullOrWhiteSpace(tableName)) - { - var table = tableClient.GetTableReference(tableName); - - result = await table.ExistsAsync(); - } - result = true; - } - catch (Exception) - { - result = false; - } - - return result - ? HealthCheckResult.Healthy($"AzureTableStorage {storageAccount.BlobStorageUri} is available") - : HealthCheckResult.Unhealthy($"AzureTableStorage {storageAccount.BlobStorageUri} is unavailable"); - - }, cacheDuration ?? builder.DefaultCacheDuration); - - return builder; - } - - public static HealthCheckBuilder AddAzureFileStorageCheck(this HealthCheckBuilder builder, string accountName, string accountKey, string shareName = null, TimeSpan? cacheDuration = null) - { - var credentials = new StorageCredentials(accountName, accountKey); - var storageAccount = new CloudStorageAccount(credentials, true); - return AddAzureFileStorageCheck(builder, storageAccount, shareName, cacheDuration); - } - - public static HealthCheckBuilder AddAzureFileStorageCheck(HealthCheckBuilder builder, CloudStorageAccount storageAccount, string shareName = null, TimeSpan? cacheDuration = null) - { - builder.AddCheck($"AzureFileStorageCheck {storageAccount.FileStorageUri} {shareName}", async () => - { - bool result; - try - { - var fileClient = storageAccount.CreateCloudFileClient(); - - var properties = await fileClient.GetServicePropertiesAsync().ConfigureAwait(false); - - if (!String.IsNullOrWhiteSpace(shareName)) - { - var share = fileClient.GetShareReference(shareName); - - result = await share.ExistsAsync(); - } - - result = true; - } - catch (Exception) - { - result = false; - } - - return result - ? HealthCheckResult.Healthy($"AzureFileStorage {storageAccount.BlobStorageUri} is available") - : HealthCheckResult.Unhealthy($"AzureFileStorage {storageAccount.BlobStorageUri} is unavailable"); - }, cacheDuration ?? builder.DefaultCacheDuration); - - return builder; - } - - public static HealthCheckBuilder AddAzureQueueStorageCheck(this HealthCheckBuilder builder, string accountName, string accountKey, string queueName = null, TimeSpan? cacheDuration = null) - { - var credentials = new StorageCredentials(accountName, accountKey); - var storageAccount = new CloudStorageAccount(credentials, true); - return AddAzureQueueStorageCheck(builder, storageAccount, queueName, cacheDuration); - } - - public static HealthCheckBuilder AddAzureQueueStorageCheck(HealthCheckBuilder builder, CloudStorageAccount storageAccount, string queueName = null, TimeSpan? cacheDuration = null) - { - builder.AddCheck($"AzureQueueStorageCheck {storageAccount.QueueStorageUri} {queueName}", async () => - { - bool result; - try - { - var queueClient = storageAccount.CreateCloudQueueClient(); - - var properties = await queueClient.GetServicePropertiesAsync().ConfigureAwait(false); - - if (!String.IsNullOrWhiteSpace(queueName)) - { - var queue = queueClient.GetQueueReference(queueName); - - result = await queue.ExistsAsync(); - } - result = true; - } - catch (Exception) - { - result = false; - } - - return result - ? HealthCheckResult.Healthy($"AzureFileStorage {storageAccount.BlobStorageUri} is available") - : HealthCheckResult.Unhealthy($"AzureFileStorage {storageAccount.BlobStorageUri} is unavailable"); - - }, cacheDuration ?? builder.DefaultCacheDuration); - - return builder; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj deleted file mode 100644 index 007f66f65..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - netstandard2.0 - false - false - false - - - - - - - - - - - - - - - - - - - diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Properties/AssemblyInfo.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Properties/AssemblyInfo.cs deleted file mode 100644 index ef88235f5..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("HealthChecks.Azure")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0c4158b7-7153-4d2e-abfa-4ce07d44f75f")] diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs deleted file mode 100644 index 1837d9638..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.SqlClient; - -namespace Microsoft.Extensions.HealthChecks -{ - // REVIEW: What are the appropriate guards for these functions? - - public static class HealthCheckBuilderSqlServerExtensions - { - public static HealthCheckBuilder AddSqlCheck(this HealthCheckBuilder builder, string name, string connectionString) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddSqlCheck(builder, name, connectionString, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddSqlCheck(this HealthCheckBuilder builder, string name, string connectionString, TimeSpan cacheDuration) - { - builder.AddCheck($"SqlCheck({name})", async () => - { - try - { - //TODO: There is probably a much better way to do this. - using (var connection = new SqlConnection(connectionString)) - { - connection.Open(); - using (var command = connection.CreateCommand()) - { - command.CommandType = CommandType.Text; - command.CommandText = "SELECT 1"; - var result = (int)await command.ExecuteScalarAsync().ConfigureAwait(false); - if (result == 1) - { - return HealthCheckResult.Healthy($"SqlCheck({name}): Healthy"); - } - - return HealthCheckResult.Unhealthy($"SqlCheck({name}): Unhealthy"); - } - } - } - catch (Exception ex) - { - return HealthCheckResult.Unhealthy($"SqlCheck({name}): Exception during check: {ex.GetType().FullName}"); - } - }, cacheDuration); - - return builder; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj deleted file mode 100644 index 0aef3c907..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheck.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheck.cs deleted file mode 100644 index 39ed087eb..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheck.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.Extensions.HealthChecks -{ - public abstract class CachedHealthCheck - { - private static readonly TypeInfo HealthCheckTypeInfo = typeof(IHealthCheck).GetTypeInfo(); - - private volatile int _writerCount; - - public CachedHealthCheck(string name, TimeSpan cacheDuration) - { - Guard.ArgumentNotNullOrEmpty(nameof(name), name); - Guard.ArgumentValid(cacheDuration.TotalMilliseconds >= 0, nameof(cacheDuration), "Cache duration must be zero (disabled) or greater than zero."); - - Name = name; - CacheDuration = cacheDuration; - } - - public IHealthCheckResult CachedResult { get; internal set; } - - public TimeSpan CacheDuration { get; } - - public DateTimeOffset CacheExpiration { get; internal set; } - - public string Name { get; } - - protected virtual DateTimeOffset UtcNow => DateTimeOffset.UtcNow; - - protected abstract IHealthCheck Resolve(IServiceProvider serviceProvider); - - public async ValueTask RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken = default(CancellationToken)) - { - while (CacheExpiration <= UtcNow) - { - // Can't use a standard lock here because of async, so we'll use this flag to determine when we should write a value, - // and the waiters who aren't allowed to write will just spin wait for the new value. - if (Interlocked.Exchange(ref _writerCount, 1) != 0) - { - await Task.Delay(5, cancellationToken).ConfigureAwait(false); - continue; - } - - try - { - var check = Resolve(serviceProvider); - CachedResult = await check.CheckAsync(cancellationToken); - } - catch (OperationCanceledException) - { - CachedResult = HealthCheckResult.Unhealthy("The health check operation timed out"); - } - catch (Exception ex) - { - CachedResult = HealthCheckResult.Unhealthy($"Exception during check: {ex.GetType().FullName}"); - } - - CacheExpiration = UtcNow + CacheDuration; - _writerCount = 0; - break; - } - - return CachedResult; - } - - public static CachedHealthCheck FromHealthCheck(string name, TimeSpan cacheDuration, IHealthCheck healthCheck) - { - Guard.ArgumentNotNull(nameof(healthCheck), healthCheck); - - return new TypeOrHealthCheck_HealthCheck(name, cacheDuration, healthCheck); - } - - public static CachedHealthCheck FromType(string name, TimeSpan cacheDuration, Type healthCheckType) - { - Guard.ArgumentNotNull(nameof(healthCheckType), healthCheckType); - Guard.ArgumentValid(HealthCheckTypeInfo.IsAssignableFrom(healthCheckType.GetTypeInfo()), nameof(healthCheckType), $"Health check must implement '{typeof(IHealthCheck).FullName}'."); - - return new TypeOrHealthCheck_Type(name, cacheDuration, healthCheckType); - } - - class TypeOrHealthCheck_HealthCheck : CachedHealthCheck - { - private readonly IHealthCheck _healthCheck; - - public TypeOrHealthCheck_HealthCheck(string name, TimeSpan cacheDuration, IHealthCheck healthCheck) : base(name, cacheDuration) - => _healthCheck = healthCheck; - - protected override IHealthCheck Resolve(IServiceProvider serviceProvider) => _healthCheck; - } - - class TypeOrHealthCheck_Type : CachedHealthCheck - { - private readonly Type _healthCheckType; - - public TypeOrHealthCheck_Type(string name, TimeSpan cacheDuration, Type healthCheckType) : base(name, cacheDuration) - => _healthCheckType = healthCheckType; - - protected override IHealthCheck Resolve(IServiceProvider serviceProvider) - => (IHealthCheck)serviceProvider.GetRequiredService(_healthCheckType); - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheckExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheckExtensions.cs deleted file mode 100644 index 2c3388709..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CachedHealthCheckExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks -{ - public static class CachedHealthCheckExtensions - { - public static ValueTask RunAsync(this CachedHealthCheck check, IServiceProvider serviceProvider) - { - Guard.ArgumentNotNull(nameof(check), check); - - return check.RunAsync(serviceProvider, CancellationToken.None); - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CheckStatus.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CheckStatus.cs deleted file mode 100644 index c5d1a093f..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CheckStatus.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.Extensions.HealthChecks -{ - public enum CheckStatus - { - Unknown, - Unhealthy, - Healthy, - Warning - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/AddCheck.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/AddCheck.cs deleted file mode 100644 index 5b7b49af0..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/AddCheck.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks -{ - public static partial class HealthCheckBuilderExtensions - { - // Lambda versions of AddCheck for Func/Func/Func - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromCheck(check), cacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromCheck(check), cacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func> check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromTaskCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func> check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromTaskCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func> check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromTaskCheck(check), cacheDuration); - } - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name, Func> check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromTaskCheck(check), cacheDuration); - } - - public static HealthCheckBuilder AddValueTaskCheck(this HealthCheckBuilder builder, string name, Func> check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromValueTaskCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddValueTaskCheck(this HealthCheckBuilder builder, string name, Func> check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromValueTaskCheck(check), builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddValueTaskCheck(this HealthCheckBuilder builder, string name, Func> check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromValueTaskCheck(check), cacheDuration); - } - - public static HealthCheckBuilder AddValueTaskCheck(this HealthCheckBuilder builder, string name, Func> check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, HealthCheck.FromValueTaskCheck(check), cacheDuration); - } - - // IHealthCheck versions of AddCheck - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string checkName, IHealthCheck check) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(checkName, check, builder.DefaultCacheDuration); - } - - // Type versions of AddCheck - - public static HealthCheckBuilder AddCheck(this HealthCheckBuilder builder, string name) where TCheck : class, IHealthCheck - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return builder.AddCheck(name, builder.DefaultCacheDuration); - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs deleted file mode 100644 index 4c958234e..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public static partial class HealthCheckBuilderExtensions - { - // Numeric checks - - public static HealthCheckBuilder AddMinValueCheck(this HealthCheckBuilder builder, string name, T minValue, Func currentValueFunc) where T : IComparable - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddMinValueCheck(builder, name, minValue, currentValueFunc, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddMinValueCheck(this HealthCheckBuilder builder, string name, T minValue, Func currentValueFunc, TimeSpan cacheDuration) - where T : IComparable - { - Guard.ArgumentNotNull(nameof(builder), builder); - Guard.ArgumentNotNullOrEmpty(nameof(name), name); - Guard.ArgumentNotNull(nameof(currentValueFunc), currentValueFunc); - - builder.AddCheck(name, () => - { - var currentValue = currentValueFunc(); - var status = currentValue.CompareTo(minValue) >= 0 ? CheckStatus.Healthy : CheckStatus.Unhealthy; - return HealthCheckResult.FromStatus( - status, - $"min={minValue}, current={currentValue}", - new Dictionary { { "min", minValue }, { "current", currentValue } } - ); - }, cacheDuration); - - return builder; - } - - public static HealthCheckBuilder AddMaxValueCheck(this HealthCheckBuilder builder, string name, T maxValue, Func currentValueFunc) where T : IComparable - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddMaxValueCheck(builder, name, maxValue, currentValueFunc, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddMaxValueCheck(this HealthCheckBuilder builder, string name, T maxValue, Func currentValueFunc, TimeSpan cacheDuration) - where T : IComparable - { - Guard.ArgumentNotNull(nameof(builder), builder); - Guard.ArgumentNotNullOrEmpty(nameof(name), name); - Guard.ArgumentNotNull(nameof(currentValueFunc), currentValueFunc); - - builder.AddCheck(name, () => - { - var currentValue = currentValueFunc(); - var status = currentValue.CompareTo(maxValue) <= 0 ? CheckStatus.Healthy : CheckStatus.Unhealthy; - return HealthCheckResult.FromStatus( - status, - $"max={maxValue}, current={currentValue}", - new Dictionary { { "max", maxValue }, { "current", currentValue } } - ); - }, cacheDuration); - - return builder; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs deleted file mode 100644 index dbd9feff2..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; - -namespace Microsoft.Extensions.HealthChecks -{ - public static partial class HealthCheckBuilderExtensions - { - // System checks - - public static HealthCheckBuilder AddPrivateMemorySizeCheck(this HealthCheckBuilder builder, long maxSize) - => AddMaxValueCheck(builder, $"PrivateMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().PrivateMemorySize64); - - public static HealthCheckBuilder AddPrivateMemorySizeCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration) - => AddMaxValueCheck(builder, $"PrivateMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().PrivateMemorySize64, cacheDuration); - - public static HealthCheckBuilder AddVirtualMemorySizeCheck(this HealthCheckBuilder builder, long maxSize) - => AddMaxValueCheck(builder, $"VirtualMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().VirtualMemorySize64); - - public static HealthCheckBuilder AddVirtualMemorySizeCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration) - => AddMaxValueCheck(builder, $"VirtualMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().VirtualMemorySize64, cacheDuration); - - public static HealthCheckBuilder AddWorkingSetCheck(this HealthCheckBuilder builder, long maxSize) - => AddMaxValueCheck(builder, $"WorkingSet({maxSize})", maxSize, () => Process.GetCurrentProcess().WorkingSet64); - - public static HealthCheckBuilder AddWorkingSetCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration) - => AddMaxValueCheck(builder, $"WorkingSet({maxSize})", maxSize, () => Process.GetCurrentProcess().WorkingSet64, cacheDuration); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs deleted file mode 100644 index 2a6cfe908..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.Extensions.HealthChecks.Internal; - -namespace Microsoft.Extensions.HealthChecks -{ - public static partial class HealthCheckBuilderExtensions - { - // Default URL check - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddUrlCheck(builder, url, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, TimeSpan cacheDuration) - => AddUrlCheck(builder, url, response => UrlChecker.DefaultUrlCheck(response), cacheDuration); - - // Func returning IHealthCheckResult - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func checkFunc) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, - Func checkFunc, - TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(checkFunc), checkFunc); - - return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)), cacheDuration); - } - - // Func returning Task - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func> checkFunc) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, - Func> checkFunc, - TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(checkFunc), checkFunc); - - return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)), cacheDuration); - } - - // Func returning ValueTask - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func> checkFunc) - { - Guard.ArgumentNotNull(nameof(builder), builder); - - return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration); - } - - public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, - Func> checkFunc, - TimeSpan cacheDuration) - { - Guard.ArgumentNotNull(nameof(builder), builder); - Guard.ArgumentNotNullOrEmpty(nameof(url), url); - Guard.ArgumentNotNull(nameof(checkFunc), checkFunc); - - var urlCheck = new UrlChecker(checkFunc, url); - builder.AddCheck($"UrlCheck({url})", () => urlCheck.CheckAsync(), cacheDuration); - return builder; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CompositeHealthCheckResult.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CompositeHealthCheckResult.cs deleted file mode 100644 index 6894ce85f..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/CompositeHealthCheckResult.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.Extensions.HealthChecks -{ - ///

- /// Represents a composite health check result built from several results. - /// - public class CompositeHealthCheckResult : IHealthCheckResult - { - private static readonly IReadOnlyDictionary _emptyData = new Dictionary(); - private readonly CheckStatus _initialStatus; - private readonly CheckStatus _partiallyHealthyStatus; - private readonly Dictionary _results = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public CompositeHealthCheckResult(CheckStatus partiallyHealthyStatus = CheckStatus.Warning, - CheckStatus initialStatus = CheckStatus.Unknown) - { - _partiallyHealthyStatus = partiallyHealthyStatus; - _initialStatus = initialStatus; - } - - public CheckStatus CheckStatus - { - get - { - var checkStatuses = new HashSet(_results.Select(x => x.Value.CheckStatus)); - if (checkStatuses.Count == 0) - { - return _initialStatus; - } - if (checkStatuses.Count == 1) - { - return checkStatuses.First(); - } - if (checkStatuses.Contains(CheckStatus.Healthy)) - { - return _partiallyHealthyStatus; - } - - return CheckStatus.Unhealthy; - } - } - - public string Description => string.Join(Environment.NewLine, _results.Select(r => $"{r.Key}: {r.Value.Description}")); - - public IReadOnlyDictionary Data - { - get - { - var result = new Dictionary(); - - foreach (var kvp in _results) - result.Add(kvp.Key, kvp.Value.Data); - - return result; - } - } - - public IReadOnlyDictionary Results => _results; - - public void Add(string name, CheckStatus status, string description) - => Add(name, status, description, null); - - public void Add(string name, CheckStatus status, string description, Dictionary data) - { - Guard.ArgumentNotNullOrEmpty(nameof(name), name); - Guard.ArgumentValid(status != CheckStatus.Unknown, nameof(status), "Cannot add 'Unknown' status to composite health check result."); - Guard.ArgumentNotNullOrEmpty(nameof(description), description); - - _results.Add(name, HealthCheckResult.FromStatus(status, description, data)); - } - - public void Add(string name, IHealthCheckResult checkResult) - { - Guard.ArgumentNotNullOrEmpty(nameof(name), name); - Guard.ArgumentNotNull(nameof(checkResult), checkResult); - - _results.Add(name, checkResult); - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheck.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheck.cs deleted file mode 100644 index 5e1caa2ff..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheck.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheck : IHealthCheck - { - protected HealthCheck(Func> check) - { - Guard.ArgumentNotNull(nameof(check), check); - - Check = check; - } - - protected Func> Check { get; } - - public ValueTask CheckAsync(CancellationToken cancellationToken = default(CancellationToken)) - => Check(cancellationToken); - - public static HealthCheck FromCheck(Func check) - => new HealthCheck(token => new ValueTask(check())); - - public static HealthCheck FromCheck(Func check) - => new HealthCheck(token => new ValueTask(check(token))); - - public static HealthCheck FromTaskCheck(Func> check) - => new HealthCheck(token => new ValueTask(check())); - - public static HealthCheck FromTaskCheck(Func> check) - => new HealthCheck(token => new ValueTask(check(token))); - - public static HealthCheck FromValueTaskCheck(Func> check) - => new HealthCheck(token => check()); - - public static HealthCheck FromValueTaskCheck(Func> check) - => new HealthCheck(check); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs deleted file mode 100644 index 006e4a6ef..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheckBuilder - { - private readonly Dictionary _checksByName; - private readonly HealthCheckGroup _currentGroup; - private readonly Dictionary _groups; - - public HealthCheckBuilder() - { - _checksByName = new Dictionary(StringComparer.OrdinalIgnoreCase); - _currentGroup = new HealthCheckGroup(string.Empty, CheckStatus.Unhealthy); - _groups = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - [string.Empty] = _currentGroup - }; - - DefaultCacheDuration = TimeSpan.FromMinutes(5); - } - - /// - /// This constructor should only be used when creating a grouped health check builder. - /// - public HealthCheckBuilder(HealthCheckBuilder rootBuilder, HealthCheckGroup currentGroup) - { - Guard.ArgumentNotNull(nameof(rootBuilder), rootBuilder); - Guard.ArgumentNotNull(nameof(currentGroup), currentGroup); - - _checksByName = rootBuilder._checksByName; - _currentGroup = currentGroup; - _groups = rootBuilder._groups; - - DefaultCacheDuration = rootBuilder.DefaultCacheDuration; - } - - /// - /// Gets the registered checks, indexed by check name. - /// - public IReadOnlyDictionary ChecksByName => _checksByName; - - /// - /// Gets the current default cache duration used when registering checks. - /// - public TimeSpan DefaultCacheDuration { get; private set; } - - /// - /// Gets the registered groups, indexed by group name. The root group's name is . - /// - public IReadOnlyDictionary Groups => _groups; - - /// - /// Registers a health check type that will later be resolved via dependency - /// injection. - /// - public HealthCheckBuilder AddCheck(string checkName, TimeSpan cacheDuration) where TCheck : class, IHealthCheck - { - Guard.ArgumentNotNullOrEmpty(nameof(checkName), checkName); - Guard.ArgumentValid(!_checksByName.ContainsKey(checkName), nameof(checkName), $"A check with name '{checkName}' has already been registered."); - - var namedCheck = CachedHealthCheck.FromType(checkName, cacheDuration, typeof(TCheck)); - - _checksByName.Add(checkName, namedCheck); - _currentGroup.ChecksInternal.Add(namedCheck); - - return this; - } - - /// - /// Registers a concrete health check to the builder. - /// - public HealthCheckBuilder AddCheck(string checkName, IHealthCheck check, TimeSpan cacheDuration) - { - Guard.ArgumentNotNullOrEmpty(nameof(checkName), checkName); - Guard.ArgumentNotNull(nameof(check), check); - Guard.ArgumentValid(!_checksByName.ContainsKey(checkName), nameof(checkName), $"A check with name '{checkName}' has already been registered."); - - var namedCheck = CachedHealthCheck.FromHealthCheck(checkName, cacheDuration, check); - - _checksByName.Add(checkName, namedCheck); - _currentGroup.ChecksInternal.Add(namedCheck); - - return this; - } - - /// - /// Creates a new health check group, to which you can add one or more health - /// checks. Uses when the group is - /// partially successful. - /// - public HealthCheckBuilder AddHealthCheckGroup(string groupName, Action groupChecks) - => AddHealthCheckGroup(groupName, groupChecks, CheckStatus.Unhealthy); - - /// - /// Creates a new health check group, to which you can add one or more health - /// checks. - /// - public HealthCheckBuilder AddHealthCheckGroup(string groupName, Action groupChecks, CheckStatus partialSuccessStatus) - { - Guard.ArgumentNotNullOrEmpty(nameof(groupName), groupName); - Guard.ArgumentNotNull(nameof(groupChecks), groupChecks); - Guard.ArgumentValid(partialSuccessStatus != CheckStatus.Unknown, nameof(partialSuccessStatus), "Check status 'Unknown' is not valid for partial success."); - Guard.ArgumentValid(!_groups.ContainsKey(groupName), nameof(groupName), $"A group with name '{groupName}' has already been registered."); - Guard.OperationValid(_currentGroup.GroupName == string.Empty, "Nested groups are not supported by HealthCheckBuilder."); - - var group = new HealthCheckGroup(groupName, partialSuccessStatus); - _groups.Add(groupName, group); - - var innerBuilder = new HealthCheckBuilder(this, group); - groupChecks(innerBuilder); - - return this; - } - - public HealthCheckBuilder WithDefaultCacheDuration(TimeSpan duration) - { - Guard.ArgumentValid(duration >= TimeSpan.Zero, nameof(duration), "Duration must be zero (disabled) or a positive duration."); - - DefaultCacheDuration = duration; - return this; - } - - public HealthCheckBuilder WithPartialSuccessStatus(CheckStatus partiallyHealthyStatus) - { - _currentGroup.PartiallyHealthyStatus = partiallyHealthyStatus; - - return this; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckGroup.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckGroup.cs deleted file mode 100644 index 18c55132b..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckGroup.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheckGroup - { - private CheckStatus _partialSuccessStatus; - - public HealthCheckGroup(string groupName, CheckStatus partialSuccessStatus) - { - Guard.ArgumentNotNull(nameof(groupName), groupName); - - GroupName = groupName; - PartiallyHealthyStatus = partialSuccessStatus; - } - - public IReadOnlyList Checks => ChecksInternal.AsReadOnly(); - - internal List ChecksInternal { get; } = new List(); - - public string GroupName { get; } - - public CheckStatus PartiallyHealthyStatus - { - get => _partialSuccessStatus; - internal set - { - Guard.ArgumentValid(value != CheckStatus.Unknown, nameof(value), "Check status 'Unknown' is not valid for partial success."); - - _partialSuccessStatus = value; - } - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResult.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResult.cs deleted file mode 100644 index d8ef80dc4..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResult.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheckResult : IHealthCheckResult - { - private static readonly IReadOnlyDictionary _emptyData = new Dictionary(); - - public CheckStatus CheckStatus { get; } - public IReadOnlyDictionary Data { get; } - public string Description { get; } - - private HealthCheckResult(CheckStatus checkStatus, string description, IReadOnlyDictionary data) - { - CheckStatus = checkStatus; - Description = description; - Data = data ?? _emptyData; - } - - public static HealthCheckResult Unhealthy(string description) - => new HealthCheckResult(CheckStatus.Unhealthy, description, null); - - public static HealthCheckResult Unhealthy(string description, IReadOnlyDictionary data) - => new HealthCheckResult(CheckStatus.Unhealthy, description, data); - - public static HealthCheckResult Healthy(string description) - => new HealthCheckResult(CheckStatus.Healthy, description, null); - - public static HealthCheckResult Healthy(string description, IReadOnlyDictionary data) - => new HealthCheckResult(CheckStatus.Healthy, description, data); - - public static HealthCheckResult Warning(string description) - => new HealthCheckResult(CheckStatus.Warning, description, null); - - public static HealthCheckResult Warning(string description, IReadOnlyDictionary data) - => new HealthCheckResult(CheckStatus.Warning, description, data); - - public static HealthCheckResult Unknown(string description) - => new HealthCheckResult(CheckStatus.Unknown, description, null); - - public static HealthCheckResult Unknown(string description, IReadOnlyDictionary data) - => new HealthCheckResult(CheckStatus.Unknown, description, data); - - public static HealthCheckResult FromStatus(CheckStatus status, string description) - => new HealthCheckResult(status, description, null); - - public static HealthCheckResult FromStatus(CheckStatus status, string description, IReadOnlyDictionary data) - => new HealthCheckResult(status, description, data); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResults.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResults.cs deleted file mode 100644 index d85dd9e39..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckResults.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheckResults - { - public IList CheckResults { get; } = new List(); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckService.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckService.cs deleted file mode 100644 index 1d2934e0e..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckService.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.Extensions.HealthChecks -{ - public class HealthCheckService : IHealthCheckService - { - private readonly HealthCheckBuilder _builder; - private readonly IReadOnlyList _groups; - private readonly HealthCheckGroup _root; - private readonly IServiceProvider _serviceProvider; - private readonly IServiceScopeFactory _serviceScopeFactory; - - public HealthCheckService(HealthCheckBuilder builder, IServiceProvider serviceProvider, IServiceScopeFactory serviceScopeFactory) - { - _builder = builder; - _groups = GetGroups().Where(group => group.GroupName != string.Empty).ToList(); - _root = GetGroup(string.Empty); - _serviceProvider = serviceProvider; - _serviceScopeFactory = serviceScopeFactory; - } - - public async Task CheckHealthAsync(CancellationToken cancellationToken = default(CancellationToken)) - { - using (var scope = GetServiceScope()) - { - var scopeServiceProvider = scope.ServiceProvider; - var groupTasks = _groups.Select(group => new { Group = group, Task = RunGroupAsync(scopeServiceProvider, group, cancellationToken) }).ToList(); - var result = await RunGroupAsync(scopeServiceProvider, _root, cancellationToken).ConfigureAwait(false); - - await Task.WhenAll(groupTasks.Select(x => x.Task)); - - foreach (var groupTask in groupTasks) - { - result.Add($"Group({groupTask.Group.GroupName})", groupTask.Task.Result); - } - - return result; - } - } - - public IReadOnlyList GetAllChecks() - => _builder.ChecksByName.Values.ToList().AsReadOnly(); - - public CachedHealthCheck GetCheck(string checkName) - => _builder.ChecksByName[checkName]; - - public HealthCheckGroup GetGroup(string groupName) - => _builder.Groups[groupName]; - - public IReadOnlyList GetGroups() - => _builder.Groups.Values.ToList().AsReadOnly(); - - private IServiceScope GetServiceScope() - => _serviceScopeFactory == null ? new UnscopedServiceProvider(_serviceProvider) : _serviceScopeFactory.CreateScope(); - - public async ValueTask RunCheckAsync(CachedHealthCheck healthCheck, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var scope = GetServiceScope()) - { - return await RunCheckAsync(scope.ServiceProvider, healthCheck, cancellationToken).ConfigureAwait(false); - } - } - - /// - /// Uses the provided service provider and executes the provided check. - /// - public ValueTask RunCheckAsync(IServiceProvider serviceProvider, CachedHealthCheck healthCheck, CancellationToken cancellationToken = default(CancellationToken)) - { - Guard.ArgumentNotNull(nameof(serviceProvider), serviceProvider); - Guard.ArgumentNotNull(nameof(healthCheck), healthCheck); - - return healthCheck.RunAsync(serviceProvider, cancellationToken); - } - - /// - /// Creates a new resolution scope from the default service provider and executes the checks in the given group. - /// - public async Task RunGroupAsync(HealthCheckGroup group, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var scope = GetServiceScope()) - return await RunGroupAsync(scope.ServiceProvider, group, cancellationToken).ConfigureAwait(false); - } - - /// - /// Uses the provided service provider and executes the checks in the given group. - /// - public async Task RunGroupAsync(IServiceProvider serviceProvider, HealthCheckGroup group, CancellationToken cancellationToken = default(CancellationToken)) - { - var result = new CompositeHealthCheckResult(group.PartiallyHealthyStatus); - var checkTasks = group.Checks.Select(check => new { Check = check, Task = check.RunAsync(serviceProvider, cancellationToken).AsTask() }).ToList(); - await Task.WhenAll(checkTasks.Select(checkTask => checkTask.Task)); - - foreach (var checkTask in checkTasks) - { - result.Add(checkTask.Check.Name, checkTask.Task.Result); - } - - return result; - } - - private class UnscopedServiceProvider : IServiceScope - { - public UnscopedServiceProvider(IServiceProvider serviceProvider) - => ServiceProvider = serviceProvider; - - public IServiceProvider ServiceProvider { get; } - - public void Dispose() { } - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckServiceCollectionExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckServiceCollectionExtensions.cs deleted file mode 100644 index 678731737..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckServiceCollectionExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using Microsoft.Extensions.HealthChecks; - -namespace Microsoft.Extensions.DependencyInjection -{ - public static class HealthCheckServiceCollectionExtensions - { - private static readonly Type HealthCheckServiceInterface = typeof(IHealthCheckService); - - public static IServiceCollection AddHealthChecks(this IServiceCollection services, Action checks) - { - Guard.OperationValid(!services.Any(descriptor => descriptor.ServiceType == HealthCheckServiceInterface), "AddHealthChecks may only be called once."); - - var builder = new HealthCheckBuilder(); - - services.AddSingleton(serviceProvider => - { - var serviceScopeFactory = serviceProvider.GetService(); - return new HealthCheckService(builder, serviceProvider, serviceScopeFactory); - }); - - checks(builder); - return services; - } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheck.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheck.cs deleted file mode 100644 index e4aa45d28..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheck.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks -{ - public interface IHealthCheck - { - ValueTask CheckAsync(CancellationToken cancellationToken = default(CancellationToken)); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckResult.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckResult.cs deleted file mode 100644 index 18a97f93c..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.Extensions.HealthChecks -{ - public interface IHealthCheckResult - { - CheckStatus CheckStatus { get; } - string Description { get; } - IReadOnlyDictionary Data { get; } - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckService.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckService.cs deleted file mode 100644 index 17a49cb00..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/IHealthCheckService.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks -{ - public interface IHealthCheckService - { - /// - /// Runs all registered health checks. - /// - Task CheckHealthAsync(CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets all registered health checks as a flat list. - /// - IReadOnlyList GetAllChecks(); - - /// - /// Gets a health check by name. - /// - CachedHealthCheck GetCheck(string checkName); - - /// - /// Gets all health checks in a group. - /// - HealthCheckGroup GetGroup(string groupName); - - /// - /// Gets all the health check groups. - /// - IReadOnlyList GetGroups(); - - /// - /// Creates a new resolution scope from the default service provider and executes the provided check. - /// - ValueTask RunCheckAsync(CachedHealthCheck healthCheck, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Uses the provided service provider and executes the provided check. - /// - ValueTask RunCheckAsync(IServiceProvider serviceProvider, CachedHealthCheck healthCheck, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Creates a new resolution scope from the default service provider and executes the checks in the given group. - /// - Task RunGroupAsync(HealthCheckGroup group, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Uses the provided service provider and executes the checks in the given group. - /// - Task RunGroupAsync(IServiceProvider serviceProvider, HealthCheckGroup group, CancellationToken cancellationToken = default(CancellationToken)); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Internal/UrlChecker.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Internal/UrlChecker.cs deleted file mode 100644 index 56800d334..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Internal/UrlChecker.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.HealthChecks.Internal -{ - public class UrlChecker - { - private readonly Func> _checkFunc; - private readonly string _url; - - public UrlChecker(Func> checkFunc, string url) - { - Guard.ArgumentNotNull(nameof(checkFunc), checkFunc); - Guard.ArgumentNotNullOrEmpty(nameof(url), url); - - _checkFunc = checkFunc; - _url = url; - } - - public CheckStatus PartiallyHealthyStatus { get; set; } = CheckStatus.Warning; - - public async Task CheckAsync() - { - using (var httpClient = CreateHttpClient()) - { - try - { - var response = await httpClient.GetAsync(_url).ConfigureAwait(false); - return await _checkFunc(response); - } - catch (Exception ex) - { - var data = new Dictionary { { "url", _url } }; - return HealthCheckResult.Unhealthy($"Exception during check: {ex.GetType().FullName}", data); - } - } - } - - private HttpClient CreateHttpClient() - { - var httpClient = GetHttpClient(); - httpClient.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true }; - return httpClient; - } - - public static async ValueTask DefaultUrlCheck(HttpResponseMessage response) - { - var status = response.IsSuccessStatusCode ? CheckStatus.Healthy : CheckStatus.Unhealthy; - var data = new Dictionary - { - { "url", response.RequestMessage.RequestUri.ToString() }, - { "status", (int)response.StatusCode }, - { "reason", response.ReasonPhrase }, - { "body", await response.Content?.ReadAsStringAsync() } - }; - return HealthCheckResult.FromStatus(status, $"status code {response.StatusCode} ({(int)response.StatusCode})", data); - } - - protected virtual HttpClient GetHttpClient() - => new HttpClient(); - } -} diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj deleted file mode 100644 index 6c102c33d..000000000 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - - - - - - diff --git a/src/BuildingBlocks/HealthChecks/src/common/Guard.cs b/src/BuildingBlocks/HealthChecks/src/common/Guard.cs deleted file mode 100644 index 9f394be51..000000000 --- a/src/BuildingBlocks/HealthChecks/src/common/Guard.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -static class Guard -{ - public static void ArgumentNotNull(string argumentName, object value) - { - if (value == null) - { - throw new ArgumentNullException(argumentName); - } - } - - public static void ArgumentNotNullOrEmpty(string argumentName, string value) - { - if (value == null) - { - throw new ArgumentNullException(argumentName); - } - if (string.IsNullOrEmpty(value)) - { - throw new ArgumentException("Value cannot be an empty string.", argumentName); - } - } - - // Use IReadOnlyCollection instead of IEnumerable to discourage double enumeration - public static void ArgumentNotNullOrEmpty(string argumentName, IReadOnlyCollection items) - { - if (items == null) - { - throw new ArgumentNullException(argumentName); - } - if (items.Count == 0) - { - throw new ArgumentException("Collection must contain at least one item.", argumentName); - } - } - - public static void ArgumentValid(bool valid, string argumentName, string exceptionMessage) - { - if (!valid) - { - throw new ArgumentException(exceptionMessage, argumentName); - } - } - - public static void OperationValid(bool valid, string exceptionMessage) - { - if (!valid) - { - throw new InvalidOperationException(exceptionMessage); - } - } -} diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs deleted file mode 100644 index 5ea3003ed..000000000 --- a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Net.Http; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http -{ - public interface IHttpClient - { - Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer"); - - Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); - - Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); - - Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); - } -} diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj deleted file mode 100644 index 276c1a23f..000000000 --- a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0 - Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http - - - - - - - - - - \ No newline at end of file diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs deleted file mode 100644 index 9fa38ee8d..000000000 --- a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs +++ /dev/null @@ -1,191 +0,0 @@ -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Polly; -using Polly.Wrap; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http -{ - /// - /// HttpClient wrapper that integrates Retry and Circuit - /// breaker policies when invoking HTTP services. - /// Based on Polly library: https://github.com/App-vNext/Polly - /// - public class ResilientHttpClient : IHttpClient - { - private readonly HttpClient _client; - private readonly ILogger _logger; - private readonly Func> _policyCreator; - private ConcurrentDictionary _policyWrappers; - private readonly IHttpContextAccessor _httpContextAccessor; - - public ResilientHttpClient(Func> policyCreator, ILogger logger, IHttpContextAccessor httpContextAccessor) - { - _client = new HttpClient(); - _logger = logger; - _policyCreator = policyCreator; - _policyWrappers = new ConcurrentDictionary(); - _httpContextAccessor = httpContextAccessor; - } - - - public Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - return DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod); - } - - public Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - return DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod); - } - - public Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - var origin = GetOriginFromUri(uri); - - return HttpInvoker(origin, async () => - { - var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri); - - SetAuthorizationHeader(requestMessage); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - if (requestId != null) - { - requestMessage.Headers.Add("x-requestid", requestId); - } - - return await _client.SendAsync(requestMessage); - }); - } - - - public Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer") - { - var origin = GetOriginFromUri(uri); - - return HttpInvoker(origin, async () => - { - var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); - - SetAuthorizationHeader(requestMessage); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - var response = await _client.SendAsync(requestMessage); - - // raise exception if HttpResponseCode 500 - // needed for circuit breaker to track fails - - if (response.StatusCode == HttpStatusCode.InternalServerError) - { - throw new HttpRequestException(); - } - - if (!response.IsSuccessStatusCode) - { - return null; - } - - return await response.Content.ReadAsStringAsync(); - }); - } - - private Task DoPostPutAsync(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - if (method != HttpMethod.Post && method != HttpMethod.Put) - { - throw new ArgumentException("Value must be either post or put.", nameof(method)); - } - - // a new StringContent must be created for each retry - // as it is disposed after each call - var origin = GetOriginFromUri(uri); - - return HttpInvoker(origin, async () => - { - var requestMessage = new HttpRequestMessage(method, uri); - - SetAuthorizationHeader(requestMessage); - - requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - if (requestId != null) - { - requestMessage.Headers.Add("x-requestid", requestId); - } - - var response = await _client.SendAsync(requestMessage); - - // raise exception if HttpResponseCode 500 - // needed for circuit breaker to track fails - - if (response.StatusCode == HttpStatusCode.InternalServerError) - { - throw new HttpRequestException(); - } - - return response; - }); - } - - private async Task HttpInvoker(string origin, Func> action) - { - var normalizedOrigin = NormalizeOrigin(origin); - - if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap)) - { - policyWrap = Policy.WrapAsync(_policyCreator(normalizedOrigin).ToArray()); - _policyWrappers.TryAdd(normalizedOrigin, policyWrap); - } - - // Executes the action applying all - // the policies defined in the wrapper - return await policyWrap.ExecuteAsync(action, new Context(normalizedOrigin)); - } - - - private static string NormalizeOrigin(string origin) - { - return origin?.Trim()?.ToLower(); - } - - private static string GetOriginFromUri(string uri) - { - var url = new Uri(uri); - - var origin = $"{url.Scheme}://{url.DnsSafeHost}:{url.Port}"; - - return origin; - } - - private void SetAuthorizationHeader(HttpRequestMessage requestMessage) - { - var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"]; - if (!string.IsNullOrEmpty(authorizationHeader)) - { - requestMessage.Headers.Add("Authorization", new List() { authorizationHeader }); - } - } - } -} diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs deleted file mode 100644 index 578168bff..000000000 --- a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http -{ - public class StandardHttpClient : IHttpClient - { - private HttpClient _client; - private ILogger _logger; - private readonly IHttpContextAccessor _httpContextAccessor; - - public StandardHttpClient(ILogger logger, IHttpContextAccessor httpContextAccessor) - { - _client = new HttpClient(); - _logger = logger; - _httpContextAccessor = httpContextAccessor; - } - - public async Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer") - { - var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); - - SetAuthorizationHeader(requestMessage); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - var response = await _client.SendAsync(requestMessage); - - if (!response.IsSuccessStatusCode) - { - return null; - } - - return await response.Content.ReadAsStringAsync(); - } - - private async Task DoPostPutAsync(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - if (method != HttpMethod.Post && method != HttpMethod.Put) - { - throw new ArgumentException("Value must be either post or put.", nameof(method)); - } - - // a new StringContent must be created for each retry - // as it is disposed after each call - - var requestMessage = new HttpRequestMessage(method, uri); - - SetAuthorizationHeader(requestMessage); - - requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - if (requestId != null) - { - requestMessage.Headers.Add("x-requestid", requestId); - } - - var response = await _client.SendAsync(requestMessage); - - // raise exception if HttpResponseCode 500 - // needed for circuit breaker to track fails - - if (response.StatusCode == HttpStatusCode.InternalServerError) - { - throw new HttpRequestException(); - } - - return response; - } - - - public async Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod); - } - - public async Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod); - } - public async Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") - { - var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri); - - SetAuthorizationHeader(requestMessage); - - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - - if (requestId != null) - { - requestMessage.Headers.Add("x-requestid", requestId); - } - - return await _client.SendAsync(requestMessage); - } - - private void SetAuthorizationHeader(HttpRequestMessage requestMessage) - { - var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"]; - if (!string.IsNullOrEmpty(authorizationHeader)) - { - requestMessage.Headers.Add("Authorization", new List() { authorizationHeader }); - } - } - } -} - diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj index 6a6632379..1d4ea7a2d 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj @@ -1,12 +1,12 @@ - + - netcoreapp2.0 + netcoreapp2.2 - - + + diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs index 858506e46..fa06e0a0b 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Polly; @@ -10,8 +11,17 @@ namespace Microsoft.AspNetCore.Hosting { public static class IWebHostExtensions { + public static bool IsInKubernetes(this IWebHost webHost) + { + var cfg = webHost.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext { + var underK8s = webHost.IsInKubernetes(); + using (var scope = webHost.Services.CreateScope()) { var services = scope.ServiceProvider; @@ -22,38 +32,49 @@ namespace Microsoft.AspNetCore.Hosting try { - logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}"); + logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); - var retry = Policy.Handle() - .WaitAndRetry(new TimeSpan[] - { + if (underK8s) + { + InvokeSeeder(seeder, context, services); + } + else + { + var retry = Policy.Handle() + .WaitAndRetry(new TimeSpan[] + { + TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), - TimeSpan.FromSeconds(10), - TimeSpan.FromSeconds(15), - }); + TimeSpan.FromSeconds(8), + }); - retry.Execute(() => - { //if the sql server container is not created on run docker compose this //migration can't fail for network related exception. The retry options for DbContext only - //apply to transient exceptions. + //apply to transient exceptions + // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) + retry.Execute(() => InvokeSeeder(seeder, context, services)); + } - context.Database - .Migrate(); - - seeder(context, services); - }); - - - logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}"); + logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); } catch (Exception ex) { - logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}"); + logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); + if (underK8s) + { + throw; // Rethrow under k8s because we rely on k8s to re-run the pod + } } } return webHost; } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } } } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs index e1637d7be..61fc7da42 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs @@ -1,4 +1,6 @@ -namespace eShopOnContainers.Core +using System; + +namespace eShopOnContainers.Core { public class GlobalSetting { @@ -6,39 +8,60 @@ public const string MockTag = "Mock"; public const string DefaultEndpoint = "http://YOUR_IP_OR_DNS_NAME"; // i.e.: "http://YOUR_IP" or "http://YOUR_DNS_NAME" - private string _baseEndpoint; - private static readonly GlobalSetting _instance = new GlobalSetting(); + private string _baseIdentityEndpoint; + private string _baseGatewayShoppingEndpoint; + private string _baseGatewayMarketingEndpoint; public GlobalSetting() { AuthToken = "INSERT AUTHENTICATION TOKEN"; - BaseEndpoint = DefaultEndpoint; + + BaseIdentityEndpoint = DefaultEndpoint; + BaseGatewayShoppingEndpoint = DefaultEndpoint; + BaseGatewayMarketingEndpoint = DefaultEndpoint; } - public static GlobalSetting Instance + public static GlobalSetting Instance { get; } = new GlobalSetting(); + + public string BaseIdentityEndpoint { - get { return _instance; } + get { return _baseIdentityEndpoint; } + set + { + _baseIdentityEndpoint = value; + UpdateEndpoint(_baseIdentityEndpoint); + } } - public string BaseEndpoint + public string BaseGatewayShoppingEndpoint { - get { return _baseEndpoint; } + get { return _baseGatewayShoppingEndpoint; } set { - _baseEndpoint = value; - UpdateEndpoint(_baseEndpoint); + _baseGatewayShoppingEndpoint = value; + UpdateGatewayShoppingEndpoint(_baseGatewayShoppingEndpoint); } } - public string ClientId { get { return "xamarin"; }} + public string BaseGatewayMarketingEndpoint + { + get { return _baseGatewayMarketingEndpoint; } + set + { + _baseGatewayMarketingEndpoint = value; + UpdateGatewayMarketingEndpoint(_baseGatewayMarketingEndpoint); + } + } + + public string ClientId { get { return "xamarin"; } } - public string ClientSecret { get { return "secret"; }} + public string ClientSecret { get { return "secret"; } } public string AuthToken { get; set; } public string RegisterWebsite { get; set; } - public string IdentityEndpoint { get; set; } + public string AuthorizeEndpoint { get; set; } public string UserInfoEndpoint { get; set; } @@ -46,23 +69,45 @@ public string LogoutEndpoint { get; set; } - public string IdentityCallback { get; set; } + public string Callback { get; set; } public string LogoutCallback { get; set; } - private void UpdateEndpoint(string baseEndpoint) + public string GatewayShoppingEndpoint { get; set; } + + public string GatewayMarketingEndpoint { get; set; } + + private void UpdateEndpoint(string endpoint) { - var identityBaseEndpoint = $"{baseEndpoint}/identity"; - RegisterWebsite = $"{identityBaseEndpoint}/Account/Register"; - LogoutCallback = $"{identityBaseEndpoint}/Account/Redirecting"; + RegisterWebsite = $"{endpoint}/Account/Register"; + LogoutCallback = $"{endpoint}/Account/Redirecting"; - var connectBaseEndpoint = $"{identityBaseEndpoint}/connect"; - IdentityEndpoint = $"{connectBaseEndpoint}/authorize"; + var connectBaseEndpoint = $"{endpoint}/connect"; + AuthorizeEndpoint = $"{connectBaseEndpoint}/authorize"; UserInfoEndpoint = $"{connectBaseEndpoint}/userinfo"; TokenEndpoint = $"{connectBaseEndpoint}/token"; LogoutEndpoint = $"{connectBaseEndpoint}/endsession"; - - IdentityCallback = $"{baseEndpoint}/xamarincallback"; + + var baseUri = ExtractBaseUri(endpoint); + Callback = $"{baseUri}/xamarincallback"; + } + + private void UpdateGatewayShoppingEndpoint(string endpoint) + { + GatewayShoppingEndpoint = $"{endpoint}"; + } + + private void UpdateGatewayMarketingEndpoint(string endpoint) + { + GatewayMarketingEndpoint = $"{endpoint}"; + } + + private string ExtractBaseUri(string endpoint) + { + var uri = new Uri(endpoint); + var baseUri = uri.GetLeftPart(System.UriPartial.Authority); + + return baseUri; } } } \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/UriHelper.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/UriHelper.cs new file mode 100644 index 000000000..0aef68db5 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/UriHelper.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace eShopOnContainers.Core.Helpers +{ + public static class UriHelper + { + public static string CombineUri(params string[] uriParts) + { + string uri = string.Empty; + if (uriParts != null && uriParts.Count() > 0) + { + char[] trims = new char[] { '\\', '/' }; + uri = (uriParts[0] ?? string.Empty).TrimEnd(trims); + for (int i = 1; i < uriParts.Count(); i++) + { + uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims)); + } + } + return uri; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Basket/BasketService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Basket/BasketService.cs index b36488f24..48814341b 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Basket/BasketService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Basket/BasketService.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using eShopOnContainers.Core.Services.RequestProvider; using eShopOnContainers.Core.Models.Basket; using eShopOnContainers.Core.Services.FixUri; +using eShopOnContainers.Core.Helpers; namespace eShopOnContainers.Core.Services.Basket { @@ -11,7 +12,7 @@ namespace eShopOnContainers.Core.Services.Basket private readonly IRequestProvider _requestProvider; private readonly IFixUriService _fixUriService; - private const string ApiUrlBase = "mobileshoppingapigw/api/v1/b/basket"; + private const string ApiUrlBase = "api/v1/b/basket"; public BasketService(IRequestProvider requestProvider, IFixUriService fixUriService) { @@ -21,12 +22,7 @@ namespace eShopOnContainers.Core.Services.Basket public async Task GetBasketAsync(string guidUser, string token) { - var builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint) - { - Path = $"{ApiUrlBase}/{guidUser}" - }; - - var uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/{guidUser}"); CustomerBasket basket; @@ -45,35 +41,23 @@ namespace eShopOnContainers.Core.Services.Basket public async Task UpdateBasketAsync(CustomerBasket customerBasket, string token) { - var builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint) - { - Path = ApiUrlBase - }; + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, ApiUrlBase); - var uri = builder.ToString(); var result = await _requestProvider.PostAsync(uri, customerBasket, token); return result; } public async Task CheckoutAsync(BasketCheckout basketCheckout, string token) { - var builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint) - { - Path = $"{ApiUrlBase}/checkout" - }; + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/checkout"); - var uri = builder.ToString(); await _requestProvider.PostAsync(uri, basketCheckout, token); } public async Task ClearBasketAsync(string guidUser, string token) { - var builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint) - { - Path = $"{ApiUrlBase}/{guidUser}" - }; + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/{guidUser}"); - var uri = builder.ToString(); await _requestProvider.DeleteAsync(uri, token); } } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Catalog/CatalogService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Catalog/CatalogService.cs index 2811416ad..a13c22cb8 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Catalog/CatalogService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Catalog/CatalogService.cs @@ -6,6 +6,7 @@ using eShopOnContainers.Core.Services.RequestProvider; using eShopOnContainers.Core.Extensions; using System.Collections.Generic; using eShopOnContainers.Core.Services.FixUri; +using eShopOnContainers.Core.Helpers; namespace eShopOnContainers.Core.Services.Catalog { @@ -14,7 +15,7 @@ namespace eShopOnContainers.Core.Services.Catalog private readonly IRequestProvider _requestProvider; private readonly IFixUriService _fixUriService; - private const string ApiUrlBase = "mobileshoppingapigw/api/v1/c/catalog"; + private const string ApiUrlBase = "api/v1/c/catalog"; public CatalogService(IRequestProvider requestProvider, IFixUriService fixUriService) { @@ -24,9 +25,7 @@ namespace eShopOnContainers.Core.Services.Catalog public async Task> FilterAsync(int catalogBrandId, int catalogTypeId) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/items/type/{catalogTypeId}/brand/{catalogBrandId}"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/items/type/{catalogTypeId}/brand/{catalogBrandId}"); CatalogRoot catalog = await _requestProvider.GetAsync(uri); @@ -38,9 +37,7 @@ namespace eShopOnContainers.Core.Services.Catalog public async Task> GetCatalogAsync() { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/items"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/items"); CatalogRoot catalog = await _requestProvider.GetAsync(uri); @@ -55,9 +52,7 @@ namespace eShopOnContainers.Core.Services.Catalog public async Task> GetCatalogBrandAsync() { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/catalogbrands"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/catalogbrands"); IEnumerable brands = await _requestProvider.GetAsync>(uri); @@ -69,9 +64,7 @@ namespace eShopOnContainers.Core.Services.Catalog public async Task> GetCatalogTypeAsync() { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/catalogtypes"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/catalogtypes"); IEnumerable types = await _requestProvider.GetAsync>(uri); diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/FixUri/FixUriService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/FixUri/FixUriService.cs index 06cfaeae3..c774cec55 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/FixUri/FixUriService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/FixUri/FixUriService.cs @@ -31,12 +31,12 @@ namespace eShopOnContainers.Core.Services.FixUri try { if (!ViewModelLocator.UseMockService - && _settingsService.UrlBase != GlobalSetting.DefaultEndpoint) + && _settingsService.IdentityEndpointBase != GlobalSetting.DefaultEndpoint) { foreach (var catalogItem in catalogItems) { MatchCollection serverResult = IpRegex.Matches(catalogItem.PictureUri); - MatchCollection localResult = IpRegex.Matches(_settingsService.UrlBase); + MatchCollection localResult = IpRegex.Matches(_settingsService.IdentityEndpointBase); if (serverResult.Count != -1 && localResult.Count != -1) { @@ -64,12 +64,12 @@ namespace eShopOnContainers.Core.Services.FixUri try { if (!ViewModelLocator.UseMockService - && _settingsService.UrlBase != GlobalSetting.DefaultEndpoint) + && _settingsService.IdentityEndpointBase != GlobalSetting.DefaultEndpoint) { foreach (var basketItem in basketItems) { MatchCollection serverResult = IpRegex.Matches(basketItem.PictureUrl); - MatchCollection localResult = IpRegex.Matches(_settingsService.UrlBase); + MatchCollection localResult = IpRegex.Matches(_settingsService.IdentityEndpointBase); if (serverResult.Count != -1 && localResult.Count != -1) { @@ -96,12 +96,12 @@ namespace eShopOnContainers.Core.Services.FixUri try { if (!ViewModelLocator.UseMockService - && _settingsService.UrlBase != GlobalSetting.DefaultEndpoint) + && _settingsService.IdentityEndpointBase != GlobalSetting.DefaultEndpoint) { foreach (var campaignItem in campaignItems) { MatchCollection serverResult = IpRegex.Matches(campaignItem.PictureUri); - MatchCollection localResult = IpRegex.Matches(_settingsService.UrlBase); + MatchCollection localResult = IpRegex.Matches(_settingsService.IdentityEndpointBase); if (serverResult.Count != -1 && localResult.Count != -1) { diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs index a9d0d2c82..0223b48c3 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs @@ -25,7 +25,7 @@ namespace eShopOnContainers.Core.Services.Identity public string CreateAuthorizationRequest() { // Create URI to authorization endpoint - var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint); + var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.AuthorizeEndpoint); // Dictionary with values for the authorize request var dic = new Dictionary(); @@ -33,7 +33,7 @@ namespace eShopOnContainers.Core.Services.Identity dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); dic.Add("response_type", "code id_token"); dic.Add("scope", "openid profile basket orders locations marketing offline_access"); - dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback); + dic.Add("redirect_uri", GlobalSetting.Instance.Callback); dic.Add("nonce", Guid.NewGuid().ToString("N")); dic.Add("code_challenge", CreateCodeChallenge()); dic.Add("code_challenge_method", "S256"); @@ -61,7 +61,7 @@ namespace eShopOnContainers.Core.Services.Identity public async Task GetTokenAsync(string code) { - string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}&code_verifier={2}", code, WebUtility.UrlEncode(GlobalSetting.Instance.IdentityCallback), _codeVerifier); + string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}&code_verifier={2}", code, WebUtility.UrlEncode(GlobalSetting.Instance.Callback), _codeVerifier); var token = await _requestProvider.PostAsync(GlobalSetting.Instance.TokenEndpoint, data, GlobalSetting.Instance.ClientId, GlobalSetting.Instance.ClientSecret); return token; } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Location/LocationService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Location/LocationService.cs index e18d335c0..b93071368 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Location/LocationService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Location/LocationService.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.Services.RequestProvider; namespace eShopOnContainers.Core.Services.Location @@ -8,6 +9,8 @@ namespace eShopOnContainers.Core.Services.Location { private readonly IRequestProvider _requestProvider; + private const string ApiUrlBase = "api/v1/l/locations"; + public LocationService(IRequestProvider requestProvider) { _requestProvider = requestProvider; @@ -15,9 +18,8 @@ namespace eShopOnContainers.Core.Services.Location public async Task UpdateUserLocation(eShopOnContainers.Core.Models.Location.Location newLocReq, string token) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = "/mobilemarketingapigw/api/v1/l/locations"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayMarketingEndpoint, ApiUrlBase); + await _requestProvider.PostAsync(uri, newLocReq, token); } } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Marketing/CampaignService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Marketing/CampaignService.cs index 2fa5eaa9e..7ff7ae50d 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Marketing/CampaignService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Marketing/CampaignService.cs @@ -1,4 +1,5 @@ using eShopOnContainers.Core.Extensions; +using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.Models.Marketing; using eShopOnContainers.Core.Services.FixUri; using eShopOnContainers.Core.Services.RequestProvider; @@ -13,7 +14,7 @@ namespace eShopOnContainers.Core.Services.Marketing private readonly IRequestProvider _requestProvider; private readonly IFixUriService _fixUriService; - private const string ApiUrlBase = "mobilemarketingapigw/api/v1/m/campaigns"; + private const string ApiUrlBase = "api/v1/m/campaigns"; public CampaignService(IRequestProvider requestProvider, IFixUriService fixUriService) { @@ -23,9 +24,7 @@ namespace eShopOnContainers.Core.Services.Marketing public async Task> GetAllCampaignsAsync(string token) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/user"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayMarketingEndpoint, $"{ApiUrlBase}/user"); CampaignRoot campaign = await _requestProvider.GetAsync(uri, token); @@ -40,9 +39,8 @@ namespace eShopOnContainers.Core.Services.Marketing public async Task GetCampaignByIdAsync(int campaignId, string token) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - builder.Path = $"{ApiUrlBase}/{campaignId}"; - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayMarketingEndpoint, $"{ApiUrlBase}/{campaignId}"); + return await _requestProvider.GetAsync(uri, token); } } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Order/OrderService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Order/OrderService.cs index fb9a0c627..3447a21d2 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Order/OrderService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Order/OrderService.cs @@ -1,4 +1,5 @@ -using eShopOnContainers.Core.Models.Basket; +using eShopOnContainers.Core.Helpers; +using eShopOnContainers.Core.Models.Basket; using eShopOnContainers.Core.Models.Orders; using eShopOnContainers.Core.Services.RequestProvider; using System; @@ -11,7 +12,7 @@ namespace eShopOnContainers.Core.Services.Order { private readonly IRequestProvider _requestProvider; - private const string ApiUrlBase = "mobileshoppingapigw/api/v1/o/orders"; + private const string ApiUrlBase = "api/v1/o/orders"; public OrderService(IRequestProvider requestProvider) { @@ -25,11 +26,7 @@ namespace eShopOnContainers.Core.Services.Order public async Task> GetOrdersAsync(string token) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - - builder.Path = ApiUrlBase; - - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, ApiUrlBase); ObservableCollection orders = await _requestProvider.GetAsync>(uri, token); @@ -42,11 +39,7 @@ namespace eShopOnContainers.Core.Services.Order { try { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - - builder.Path = $"{ApiUrlBase}/{orderId}"; - - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/{orderId}"); Models.Orders.Order order = await _requestProvider.GetAsync(uri, token); @@ -78,13 +71,10 @@ namespace eShopOnContainers.Core.Services.Order public async Task CancelOrderAsync(int orderId, string token) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BaseEndpoint); - - builder.Path = $"{ApiUrlBase}/cancel"; + var uri = UriHelper.CombineUri(GlobalSetting.Instance.GatewayShoppingEndpoint, $"{ApiUrlBase}/cancel"); var cancelOrderCommand = new CancelOrderCommand(orderId); - string uri = builder.ToString(); var header = "x-requestid"; try diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/ISettingsService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/ISettingsService.cs index 69ede7b72..c110f98e3 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/ISettingsService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/ISettingsService.cs @@ -7,7 +7,9 @@ namespace eShopOnContainers.Core.Services.Settings string AuthAccessToken { get; set; } string AuthIdToken { get; set; } bool UseMocks { get; set; } - string UrlBase { get; set; } + string IdentityEndpointBase { get; set; } + string GatewayShoppingEndpointBase { get; set; } + string GatewayMarketingEndpointBase { get; set; } bool UseFakeLocation { get; set; } string Latitude { get; set; } string Longitude { get; set; } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/SettingsService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/SettingsService.cs index ca3e03c04..76dee8ddd 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/SettingsService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Settings/SettingsService.cs @@ -11,7 +11,9 @@ namespace eShopOnContainers.Core.Services.Settings private const string AccessToken = "access_token"; private const string IdToken = "id_token"; private const string IdUseMocks = "use_mocks"; - private const string IdUrlBase = "url_base"; + private const string IdIdentityBase = "url_base"; + private const string IdGatewayMarketingBase = "url_marketing"; + private const string IdGatewayShoppingBase = "url_shopping"; private const string IdUseFakeLocation = "use_fake_location"; private const string IdLatitude = "latitude"; private const string IdLongitude = "longitude"; @@ -23,8 +25,9 @@ namespace eShopOnContainers.Core.Services.Settings private readonly bool AllowGpsLocationDefault = false; private readonly double FakeLatitudeDefault = 47.604610d; private readonly double FakeLongitudeDefault = -122.315752d; - private readonly string UrlBaseDefault = GlobalSetting.Instance.BaseEndpoint; - + private readonly string UrlIdentityDefault = GlobalSetting.Instance.BaseIdentityEndpoint; + private readonly string UrlGatewayMarketingDefault = GlobalSetting.Instance.BaseGatewayMarketingEndpoint; + private readonly string UrlGatewayShoppingDefault = GlobalSetting.Instance.BaseGatewayShoppingEndpoint; #endregion #region Settings Properties @@ -47,10 +50,22 @@ namespace eShopOnContainers.Core.Services.Settings set => AddOrUpdateValue(IdUseMocks, value); } - public string UrlBase + public string IdentityEndpointBase + { + get => GetValueOrDefault(IdIdentityBase, UrlIdentityDefault); + set => AddOrUpdateValue(IdIdentityBase, value); + } + + public string GatewayShoppingEndpointBase + { + get => GetValueOrDefault(IdGatewayShoppingBase, UrlGatewayShoppingDefault); + set => AddOrUpdateValue(IdGatewayShoppingBase, value); + } + + public string GatewayMarketingEndpointBase { - get => GetValueOrDefault(IdUrlBase, UrlBaseDefault); - set => AddOrUpdateValue(IdUrlBase, value); + get => GetValueOrDefault(IdGatewayMarketingBase, UrlGatewayMarketingDefault); + set => AddOrUpdateValue(IdGatewayMarketingBase, value); } public bool UseFakeLocation diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/User/UserService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/User/UserService.cs index e52d24489..6056fcf7f 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/User/UserService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/User/UserService.cs @@ -1,4 +1,5 @@ -using eShopOnContainers.Core.Models.User; +using eShopOnContainers.Core.Helpers; +using eShopOnContainers.Core.Models.User; using eShopOnContainers.Core.Services.RequestProvider; using System; using System.Threading.Tasks; @@ -16,8 +17,8 @@ namespace eShopOnContainers.Core.Services.User public async Task GetUserInfoAsync(string authToken) { - UriBuilder builder = new UriBuilder(GlobalSetting.Instance.UserInfoEndpoint); - string uri = builder.ToString(); + var uri = UriHelper.CombineUri(GlobalSetting.Instance.UserInfoEndpoint); + var userInfo = await _requestProvider.GetAsync(uri, authToken); return userInfo; } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs index acb5e6636..30efc544d 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs @@ -29,7 +29,12 @@ namespace eShopOnContainers.Core.ViewModels.Base { DialogService = ViewModelLocator.Resolve(); NavigationService = ViewModelLocator.Resolve(); - GlobalSetting.Instance.BaseEndpoint = ViewModelLocator.Resolve().UrlBase; + + var settingsService = ViewModelLocator.Resolve(); + + GlobalSetting.Instance.BaseIdentityEndpoint = settingsService.IdentityEndpointBase; + GlobalSetting.Instance.BaseGatewayShoppingEndpoint = settingsService.GatewayShoppingEndpointBase; + GlobalSetting.Instance.BaseGatewayMarketingEndpoint = settingsService.GatewayMarketingEndpointBase; } public virtual Task InitializeAsync(object navigationData) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs index 2ed8cf83c..cc04deba4 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs @@ -234,7 +234,7 @@ namespace eShopOnContainers.Core.ViewModels IsLogin = false; LoginUrl = _identityService.CreateAuthorizationRequest(); } - else if (unescapedUrl.Contains(GlobalSetting.Instance.IdentityCallback)) + else if (unescapedUrl.Contains(GlobalSetting.Instance.Callback)) { var authResponse = new AuthorizeResponse(url); if (!string.IsNullOrWhiteSpace(authResponse.Code)) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/SettingsViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/SettingsViewModel.cs index 1969880cd..9f8b42b2c 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/SettingsViewModel.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/SettingsViewModel.cs @@ -13,16 +13,12 @@ namespace eShopOnContainers.Core.ViewModels { public class SettingsViewModel : ViewModelBase { - private string _titleUseAzureServices; - private string _descriptionUseAzureServices; private bool _useAzureServices; - private string _titleUseFakeLocation; - private string _descriptionUseFakeLocation; private bool _allowGpsLocation; - private string _titleAllowGpsLocation; - private string _descriptionAllowGpsLocation; private bool _useFakeLocation; - private string _endpoint; + private string _identityEndpoint; + private string _gatewayShoppingEndpoint; + private string _gatewayMarketingEndpoint; private double _latitude; private double _longitude; private string _gpsWarningMessage; @@ -38,7 +34,9 @@ namespace eShopOnContainers.Core.ViewModels _dependencyService = dependencyService; _useAzureServices = !_settingsService.UseMocks; - _endpoint = _settingsService.UrlBase; + _identityEndpoint = _settingsService.IdentityEndpointBase; + _gatewayShoppingEndpoint = _settingsService.GatewayShoppingEndpointBase; + _gatewayMarketingEndpoint = _settingsService.GatewayMarketingEndpointBase; _latitude = double.Parse(_settingsService.Latitude, CultureInfo.CurrentCulture); _longitude = double.Parse(_settingsService.Longitude, CultureInfo.CurrentCulture); _useFakeLocation = _settingsService.UseFakeLocation; @@ -48,21 +46,16 @@ namespace eShopOnContainers.Core.ViewModels public string TitleUseAzureServices { - get => _titleUseAzureServices; - set - { - _titleUseAzureServices = value; - RaisePropertyChanged(() => TitleUseAzureServices); - } + get { return !UseAzureServices ? "Use Mock Services" : "Use Microservices/Containers from eShopOnContainers"; } } public string DescriptionUseAzureServices { - get => _descriptionUseAzureServices; - set + get { - _descriptionUseAzureServices = value; - RaisePropertyChanged(() => DescriptionUseAzureServices); + return !UseAzureServices + ? "Mock Services are simulated objects that mimic the behavior of real services using a controlled approach." + : "When enabling the use of microservices/containers, the app will attempt to use real services deployed as Docker/Kubernetes containers at the specified base endpoint, which will must be reachable through the network."; } } @@ -72,30 +65,23 @@ namespace eShopOnContainers.Core.ViewModels set { _useAzureServices = value; - UpdateUseAzureServices(); - RaisePropertyChanged(() => UseAzureServices); } } public string TitleUseFakeLocation { - get => _titleUseFakeLocation; - set - { - _titleUseFakeLocation = value; - RaisePropertyChanged(() => TitleUseFakeLocation); - } + get { return !UseFakeLocation ? "Use Real Location" : "Use Fake Location"; } } public string DescriptionUseFakeLocation { - get => _descriptionUseFakeLocation; - set + get { - _descriptionUseFakeLocation = value; - RaisePropertyChanged(() => DescriptionUseFakeLocation); + return !UseFakeLocation + ? "When enabling location, the app will attempt to use the location from the device." + : "Fake Location data is added for marketing campaign testing."; } } @@ -105,30 +91,23 @@ namespace eShopOnContainers.Core.ViewModels set { _useFakeLocation = value; - UpdateFakeLocation(); - RaisePropertyChanged(() => UseFakeLocation); } } public string TitleAllowGpsLocation { - get => _titleAllowGpsLocation; - set - { - _titleAllowGpsLocation = value; - RaisePropertyChanged(() => TitleAllowGpsLocation); - } + get { return !AllowGpsLocation ? "GPS Location Disabled" : "GPS Location Enabled"; } } public string DescriptionAllowGpsLocation { - get => _descriptionAllowGpsLocation; - set + get { - _descriptionAllowGpsLocation = value; - RaisePropertyChanged(() => DescriptionAllowGpsLocation); + return !AllowGpsLocation + ? "When disabling location, you won't receive location campaigns based upon your location." + : "When enabling location, you'll receive location campaigns based upon your location."; } } @@ -142,19 +121,45 @@ namespace eShopOnContainers.Core.ViewModels } } - public string Endpoint + public string IdentityEndpoint { - get => _endpoint; + get => _identityEndpoint; set { - _endpoint = value; + _identityEndpoint = value; + if (!string.IsNullOrEmpty(_identityEndpoint)) + { + UpdateIdentityEndpoint(); + } + RaisePropertyChanged(() => IdentityEndpoint); + } + } - if (!string.IsNullOrEmpty(_endpoint)) + public string GatewayShoppingEndpoint + { + get => _gatewayShoppingEndpoint; + set + { + _gatewayShoppingEndpoint = value; + if (!string.IsNullOrEmpty(_gatewayShoppingEndpoint)) { - UpdateEndpoint(); + UpdateGatewayShoppingEndpoint(); } + RaisePropertyChanged(() => GatewayShoppingEndpoint); + } + } - RaisePropertyChanged(() => Endpoint); + public string GatewayMarketingEndpoint + { + get => _gatewayMarketingEndpoint; + set + { + _gatewayMarketingEndpoint = value; + if (!string.IsNullOrEmpty(_gatewayMarketingEndpoint)) + { + UpdateGatewayMarketingEndpoint(); + } + RaisePropertyChanged(() => GatewayMarketingEndpoint); } } @@ -164,9 +169,7 @@ namespace eShopOnContainers.Core.ViewModels set { _latitude = value; - UpdateLatitude(); - RaisePropertyChanged(() => Latitude); } } @@ -177,9 +180,7 @@ namespace eShopOnContainers.Core.ViewModels set { _longitude = value; - UpdateLongitude(); - RaisePropertyChanged(() => Longitude); } } @@ -190,9 +191,7 @@ namespace eShopOnContainers.Core.ViewModels set { _allowGpsLocation = value; - UpdateAllowGpsLocation(); - RaisePropertyChanged(() => AllowGpsLocation); } } @@ -207,19 +206,11 @@ namespace eShopOnContainers.Core.ViewModels public ICommand ToggleAllowGpsLocationCommand => new Command(ToggleAllowGpsLocation); - public override Task InitializeAsync(object navigationData) - { - UpdateInfoUseAzureServices(); - UpdateInfoFakeLocation(); - UpdateInfoAllowGpsLocation(); - - return base.InitializeAsync(navigationData); - } - private async Task ToggleMockServicesAsync() { ViewModelLocator.UpdateDependencies(!UseAzureServices); - UpdateInfoUseAzureServices(); + RaisePropertyChanged(() => TitleUseAzureServices); + RaisePropertyChanged(() => DescriptionUseAzureServices); var previousPageViewModel = NavigationService.PreviousPageViewModel; if (previousPageViewModel != null) @@ -243,7 +234,8 @@ namespace eShopOnContainers.Core.ViewModels private void ToggleFakeLocationAsync() { ViewModelLocator.UpdateDependencies(!UseAzureServices); - UpdateInfoFakeLocation(); + RaisePropertyChanged(() => TitleUseFakeLocation); + RaisePropertyChanged(() => DescriptionUseFakeLocation); } private async Task ToggleSendLocationAsync() @@ -263,63 +255,30 @@ namespace eShopOnContainers.Core.ViewModels private void ToggleAllowGpsLocation() { - UpdateInfoAllowGpsLocation(); + RaisePropertyChanged(() => TitleAllowGpsLocation); + RaisePropertyChanged(() => DescriptionAllowGpsLocation); } - private void UpdateInfoUseAzureServices() + private void UpdateUseAzureServices() { - if (!UseAzureServices) - { - TitleUseAzureServices = "Use Mock Services"; - DescriptionUseAzureServices = "Mock Services are simulated objects that mimic the behavior of real services using a controlled approach."; - } - else - { - TitleUseAzureServices = "Use Microservices/Containers from eShopOnContainers"; - DescriptionUseAzureServices = "When enabling the use of microservices/containers, the app will attempt to use real services deployed as Docker containers at the specified base endpoint, which will must be reachable through the network."; - } + // Save use mocks services to local storage + _settingsService.UseMocks = !_useAzureServices; } - private void UpdateInfoFakeLocation() + private void UpdateIdentityEndpoint() { - if (!UseFakeLocation) - { - TitleUseFakeLocation = "Use Real Location"; - DescriptionUseFakeLocation = "When enabling location, the app will attempt to use the location from the device."; - - } - else - { - TitleUseFakeLocation = "Use Fake Location"; - DescriptionUseFakeLocation = "Fake Location data is added for marketing campaign testing."; - } + // Update remote endpoint (save to local storage) + GlobalSetting.Instance.BaseIdentityEndpoint = _settingsService.IdentityEndpointBase = _identityEndpoint; } - private void UpdateInfoAllowGpsLocation() - { - if (!AllowGpsLocation) - { - TitleAllowGpsLocation = "GPS Location Disabled"; - DescriptionAllowGpsLocation = "When disabling location, you won't receive location campaigns based upon your location."; - } - else - { - TitleAllowGpsLocation = "GPS Location Enabled"; - DescriptionAllowGpsLocation = "When enabling location, you'll receive location campaigns based upon your location."; - - } - } - - private void UpdateUseAzureServices() + private void UpdateGatewayShoppingEndpoint() { - // Save use mocks services to local storage - _settingsService.UseMocks = !_useAzureServices; + GlobalSetting.Instance.BaseGatewayShoppingEndpoint = _settingsService.GatewayShoppingEndpointBase = _gatewayShoppingEndpoint; } - private void UpdateEndpoint() + private void UpdateGatewayMarketingEndpoint() { - // Update remote endpoint (save to local storage) - GlobalSetting.Instance.BaseEndpoint = _settingsService.UrlBase = _endpoint; + GlobalSetting.Instance.BaseGatewayMarketingEndpoint = _settingsService.GatewayMarketingEndpointBase = _gatewayMarketingEndpoint; } private void UpdateFakeLocation() diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/SettingsView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/SettingsView.xaml index 968b6321b..465f6d0ba 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/SettingsView.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/SettingsView.xaml @@ -2,12 +2,12 @@ @@ -92,7 +92,7 @@ - + @@ -116,195 +116,204 @@ Animation="{StaticResource MockServicesAnimation}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -