diff --git a/.env b/.env
index 4a7e37cccc..36fecb396f 100644
--- a/.env
+++ b/.env
@@ -15,6 +15,7 @@ OPENSEARCH_IMAGE=opensearchproject/opensearch:2.16.0
POSTGRES_IMAGE=postgres:16.4
PROMETHEUS_IMAGE=quay.io/prometheus/prometheus:v2.54.1
VALKEY_IMAGE=valkey/valkey:8.0-alpine
+MONGO_IMAGE=mongo:8.0.0-rc9
# must also update the version arg in ./test/tracetesting/Dockerfile
TRACETEST_IMAGE=kubeshop/tracetest:v1.5.2
@@ -138,6 +139,11 @@ KAFKA_SERVICE_DOCKERFILE=./src/kafka/Dockerfile
VALKEY_PORT=6379
VALKEY_ADDR=valkey-cart:${VALKEY_PORT}
+# MongoDB
+MONGO_PORT=27017
+MONGO_USERNAME=mongo
+MONGO_PASSWORD=mongo_product_catalog
+
# ********************
# Telemetry Components
# ********************
diff --git a/.github/workflows/buildAndPushImage-productcatalogservice.yml b/.github/workflows/buildAndPushImage-productcatalogservice.yml
new file mode 100644
index 0000000000..a6363b9d37
--- /dev/null
+++ b/.github/workflows/buildAndPushImage-productcatalogservice.yml
@@ -0,0 +1,45 @@
+name: buildAndPushImage
+
+on:
+ push:
+ branches:
+ - main
+
+env:
+ IMAGE_URL: ghcr.io/ust-demaf
+ IMAGE_NAME: productcatalogservice
+ IMAGE_TAG: 1.11.1
+
+jobs:
+ build-using-dockerfile-push-2-ghcr:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+ with:
+ platforms: linux/amd64, linux/arm64
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ with:
+ platforms: linux/amd64, linux/arm64
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ # Build and push the image
+ - name: Build and push
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ file: ./src/productcatalogservice/Dockerfile
+ platforms: linux/amd64, linux/arm64
+ push: true
+ tags: ${{ env.IMAGE_URL }}/demo:${{ env.IMAGE_TAG }}-${{ env.IMAGE_NAME }}
+ provenance: false
diff --git a/README.md b/README.md
index 5d6383845d..a24e43b29a 100644
--- a/README.md
+++ b/README.md
@@ -1,140 +1,64 @@
# OpenTelemetry Demo
-[![Slack](https://img.shields.io/badge/slack-@cncf/otel/demo-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C03B4CWV4DA)
-[![Version](https://img.shields.io/github/v/release/open-telemetry/opentelemetry-demo?color=blueviolet)](https://github.com/open-telemetry/opentelemetry-demo/releases)
-[![Commits](https://img.shields.io/github/commits-since/open-telemetry/opentelemetry-demo/latest?color=ff69b4&include_prereleases)](https://github.com/open-telemetry/opentelemetry-demo/graphs/commit-activity)
-[![Downloads](https://img.shields.io/docker/pulls/otel/demo)](https://hub.docker.com/r/otel/demo)
-[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?color=red)](https://github.com/open-telemetry/opentelemetry-demo/blob/main/LICENSE)
-[![Integration Tests](https://github.com/open-telemetry/opentelemetry-demo/actions/workflows/run-integration-tests.yml/badge.svg)](https://github.com/open-telemetry/opentelemetry-demo/actions/workflows/run-integration-tests.yml)
-[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/opentelemetry-demo)](https://artifacthub.io/packages/helm/opentelemetry-helm/opentelemetry-demo)
-[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9247/badge)](https://www.bestpractices.dev/en/projects/9247)
-
-## Welcome to the OpenTelemetry Astronomy Shop Demo
+## Welcome to the OpenTelemetry Astronomy Shop Demo with DeMAF extension
This repository contains the OpenTelemetry Astronomy Shop, a microservice-based
distributed system intended to illustrate the implementation of OpenTelemetry in
a near real-world environment.
-Our goals are threefold:
+FOR THE ORIGINAL README [CLICK HERE](./README_original.md).
+
+The purpose of this fork is to extend the Astronomy Shop in three ways:
+
+- Add a database to showcase that a persistence layer can also be part of the architecture without causing any problems.
+- Create a deployment model to deploy the shop using [Ansible](https://docs.ansible.com/) and [Terraform](https://developer.hashicorp.com/terraform/docs) besides the given [Docker-Compose](https://opentelemetry.io/docs/demo/docker_deployment/) and [Kubernetes](https://opentelemetry.io/docs/demo/kubernetes_deployment/).
+- Add translated EDMM models for [Kubernetes](./edmm/otel-store_k8s_translated.yaml), [Ansible](./edmm/otel-store_ansible_translated.yaml) and [Terraform](./edmm/otel-store_terraform_translated.yaml) to showcase the transformation result of those three DeMAF plugins in [EDMM](https://github.com/UST-EDMM).
+
+
+### Database Integration
+The database integration ensures that also a persistence layer is used in the provided demo-application,
+making the architecture more comprehensive.
+
+Therefore, a [MongoDB](http://mongodb.com) is added, which adds the products of the shop into the database as JSON entries.
+In the default variant of the astronomy shop, only a plain file is used to provide the products.
+
+Thus, the logic of the `productcatalogservice` is adapted, to initialize and use the additionally provided MongoDB.
+
+The changes of the `productcatalogservice` and the addition of the MongoDB is integrated into all deployment variants in this fork.
+
+### Translation to Ansible
+
+To verify the [Ansible MPS Plugin](https://github.com/UST-DeMAF/ansible-mps-plugin) the Astronomy Shop is available as Ansible installation.
+It is based on the [Docker-Compose](https://opentelemetry.io/docs/demo/docker_deployment/) and installs all components of the shop as docker containers on the local Docker runtime.
+For each component there is a dedicated Ansible Role representing the loose coupling of the components.
+
+A usage guide can be found in the dedicated [README in /ansible](./ansible/README.md).
+
+### Translation to Terraform
+
+To verify the [Terraform MPS Plugin](https://github.com/UST-DeMAF/terraform-mps-plugin) the Astronomy Shop is available as Terraform installation.
+It is based on the [Docker-Compose](https://opentelemetry.io/docs/demo/docker_deployment/) and installs all components of the shop as docker containers on the local Docker runtime.
+
+A usage guide can be found in the dedicated [README in /terraform](./terraform/README.md).
+
+### EDMM Models
+
+For all three evaluated technologies (Ansible, Terraform, Kubernetes) there is a transformed target model available.
+
+The target EDMM models can be found in the [/edmm directory](./edmm)
+
+In each model the goal is to retrieve a component for each deployed Astronomy Shop component
+and as many _connects-to_ and _hosted_on_ relations as possible.
+
+This in common, there are also differences in the target models.
+
+Due to the imperative character of Ansible, in the [Ansible target model](./edmm/otel-store_ansible_translated.yaml), each component has operations representing the installation of the Docker containers.
-- Provide a realistic example of a distributed system that can be used to
- demonstrate OpenTelemetry instrumentation and observability.
-- Build a base for vendors, tooling authors, and others to extend and
- demonstrate their OpenTelemetry integrations.
-- Create a living example for OpenTelemetry contributors to use for testing new
- versions of the API, SDK, and other components or enhancements.
+In the [Terraform target model](./edmm/otel-store_terraform_translated.yaml), there are common component types for all _docker_containers_,
+as they all use the same terraform ressource type. This is different in the other two evaluated technologies, where each component has a dedicated type.
-We've already made [huge
-progress](https://github.com/open-telemetry/opentelemetry-demo/blob/main/CHANGELOG.md),
-and development is ongoing. We hope to represent the full feature set of
-OpenTelemetry across its languages in the future.
-
-If you'd like to help (**which we would love**), check out our [contributing
-guidance](./CONTRIBUTING.md).
-
-If you'd like to extend this demo or maintain a fork of it, read our
-[fork guidance](https://opentelemetry.io/docs/demo/forking/).
-
-## Quick start
-
-You can be up and running with the demo in a few minutes. Check out the docs for
-your preferred deployment method:
-
-- [Docker](https://opentelemetry.io/docs/demo/docker_deployment/)
-- [Kubernetes](https://opentelemetry.io/docs/demo/kubernetes_deployment/)
-
-## Documentation
-
-For detailed documentation, see [Demo Documentation][docs]. If you're curious
-about a specific feature, the [docs landing page][docs] can point you in the
-right direction.
-
-## Demos featuring the Astronomy Shop
-
-We welcome any vendor to fork the project to demonstrate their services and
-adding a link below. The community is committed to maintaining the project and
-keeping it up to date for you.
-
-| | | |
-|-----------------------------------------|-----------------------------|----------------------------------------------------------------|
-| [AlibabaCloud LogService][AlibabaCloud] | [Elastic][Elastic] | [New Relic][NewRelic] |
-| [AppDynamics][AppDynamics] | [Google Cloud][GoogleCloud] | [OpenSearch][OpenSearch] |
-| [Aspecto][Aspecto] | [Grafana Labs][GrafanaLabs] | [Sentry][Sentry] |
-| [Axiom][Axiom] | [Guance][Guance] | [ServiceNow Cloud Observability][ServiceNowCloudObservability] |
-| [Axoflow][Axoflow] | [Helios][Helios] | [Splunk][Splunk] |
-| [Azure Data Explorer][Azure] | [Honeycomb.io][Honeycombio] | [Sumo Logic][SumoLogic] |
-| [Coralogix][Coralogix] | [Instana][Instana] | [TelemetryHub][TelemetryHub] |
-| [Dash0][Dash0] | [Kloudfuse][Kloudfuse] | [Teletrace][Teletrace] |
-| [Datadog][Datadog] | [Liatrio][Liatrio] | [Tracetest][Tracetest] |
-| [Dynatrace][Dynatrace] | [Logz.io][Logzio] | [Uptrace][Uptrace] |
-
-## Contributing
-
-To get involved with the project see our [CONTRIBUTING](CONTRIBUTING.md)
-documentation. Our [SIG Calls](CONTRIBUTING.md#join-a-sig-call) are every other
-Monday at 8:30 AM PST and anyone is welcome.
-
-## Project leadership
-
-[Maintainers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer)
-([@open-telemetry/demo-maintainers](https://github.com/orgs/open-telemetry/teams/demo-maintainers)):
-
-- [Juliano Costa](https://github.com/julianocosta89), Datadog
-- [Mikko Viitanen](https://github.com/mviitane), Dynatrace
-- [Pierre Tessier](https://github.com/puckpuck), Honeycomb
-
-[Approvers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver)
-([@open-telemetry/demo-approvers](https://github.com/orgs/open-telemetry/teams/demo-approvers)):
-
-- [Cedric Ziel](https://github.com/cedricziel) Grafana Labs
-- [Penghan Wang](https://github.com/wph95), AppDynamics
-- [Reiley Yang](https://github.com/reyang), Microsoft
-- [Roger Coll](https://github.com/rogercoll), Elastic
-- [Ziqi Zhao](https://github.com/fatsheep9146), Alibaba
-
-Emeritus:
-
-- [Austin Parker](https://github.com/austinlparker)
-- [Carter Socha](https://github.com/cartersocha)
-- [Michael Maxwell](https://github.com/mic-max)
-- [Morgan McLean](https://github.com/mtwo)
-
-### Thanks to all the people who have contributed
-
-[![contributors](https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-demo)](https://github.com/open-telemetry/opentelemetry-demo/graphs/contributors)
-
-[docs]: https://opentelemetry.io/docs/demo/
-
-
-
-[AlibabaCloud]: https://github.com/aliyun-sls/opentelemetry-demo
-[AppDynamics]: https://www.appdynamics.com/blog/cloud/how-to-observe-opentelemetry-demo-app-in-appdynamics-cloud/
-[Aspecto]: https://github.com/aspecto-io/opentelemetry-demo
-[Axiom]: https://play.axiom.co/axiom-play-qf1k/dashboards/otel.traces.otel-demo-traces
-[Axoflow]: https://axoflow.com/opentelemetry-support-in-more-detail-in-axosyslog-and-syslog-ng/
-[Azure]: https://github.com/Azure/Azure-kusto-opentelemetry-demo
-[Coralogix]: https://coralogix.com/blog/configure-otel-demo-send-telemetry-data-coralogix
-[Dash0]: https://github.com/dash0hq/opentelemetry-demo
-[Datadog]: https://docs.datadoghq.com/opentelemetry/guide/otel_demo_to_datadog
-[Dynatrace]: https://www.dynatrace.com/news/blog/opentelemetry-demo-application-with-dynatrace/
-[Elastic]: https://github.com/elastic/opentelemetry-demo
-[GoogleCloud]: https://github.com/GoogleCloudPlatform/opentelemetry-demo
-[GrafanaLabs]: https://github.com/grafana/opentelemetry-demo
-[Guance]: https://github.com/GuanceCloud/opentelemetry-demo
-[Helios]: https://otelsandbox.gethelios.dev
-[Honeycombio]: https://github.com/honeycombio/opentelemetry-demo
-[Instana]: https://github.com/instana/opentelemetry-demo
-[Kloudfuse]: https://github.com/kloudfuse/opentelemetry-demo
-[Liatrio]: https://github.com/liatrio/opentelemetry-demo
-[Logzio]: https://logz.io/learn/how-to-run-opentelemetry-demo-with-logz-io/
-[NewRelic]: https://github.com/newrelic/opentelemetry-demo
-[OpenSearch]: https://github.com/opensearch-project/opentelemetry-demo
-[Sentry]: https://github.com/getsentry/opentelemetry-demo
-[ServiceNowCloudObservability]: https://docs.lightstep.com/otel/quick-start-operator#send-data-from-the-opentelemetry-demo
-[Splunk]: https://github.com/signalfx/opentelemetry-demo
-[SumoLogic]: https://www.sumologic.com/blog/common-opentelemetry-demo-application/
-[TelemetryHub]: https://github.com/TelemetryHub/opentelemetry-demo/tree/telemetryhub-backend
-[Teletrace]: https://github.com/teletrace/opentelemetry-demo
-[Tracetest]: https://github.com/kubeshop/opentelemetry-demo
-[Uptrace]: https://github.com/uptrace/uptrace/tree/master/example/opentelemetry-demo
+For the Kubernetes model there are two variants. The [first](./edmm/otel-store_k8s_translated.yaml) is the actual result of the translation, lacking _hosted_on_ relations.
+That is, as the Kubernetes plugin only creates _hosted_on_ relations when a component named _container_runtime_ with a matching type is present in the TADM.
+Therefore, there is a [second target model](./edmm/otel-store_k8s_translated_with_container_runtime.yaml) where this _container_runtime_ has been manually added, before creating the relations.
+Thus, all components obtain a _hosted_on_ relation.
\ No newline at end of file
diff --git a/README_original.md b/README_original.md
new file mode 100644
index 0000000000..5d6383845d
--- /dev/null
+++ b/README_original.md
@@ -0,0 +1,140 @@
+
+# OpenTelemetry Demo
+
+[![Slack](https://img.shields.io/badge/slack-@cncf/otel/demo-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C03B4CWV4DA)
+[![Version](https://img.shields.io/github/v/release/open-telemetry/opentelemetry-demo?color=blueviolet)](https://github.com/open-telemetry/opentelemetry-demo/releases)
+[![Commits](https://img.shields.io/github/commits-since/open-telemetry/opentelemetry-demo/latest?color=ff69b4&include_prereleases)](https://github.com/open-telemetry/opentelemetry-demo/graphs/commit-activity)
+[![Downloads](https://img.shields.io/docker/pulls/otel/demo)](https://hub.docker.com/r/otel/demo)
+[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?color=red)](https://github.com/open-telemetry/opentelemetry-demo/blob/main/LICENSE)
+[![Integration Tests](https://github.com/open-telemetry/opentelemetry-demo/actions/workflows/run-integration-tests.yml/badge.svg)](https://github.com/open-telemetry/opentelemetry-demo/actions/workflows/run-integration-tests.yml)
+[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/opentelemetry-demo)](https://artifacthub.io/packages/helm/opentelemetry-helm/opentelemetry-demo)
+[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9247/badge)](https://www.bestpractices.dev/en/projects/9247)
+
+## Welcome to the OpenTelemetry Astronomy Shop Demo
+
+This repository contains the OpenTelemetry Astronomy Shop, a microservice-based
+distributed system intended to illustrate the implementation of OpenTelemetry in
+a near real-world environment.
+
+Our goals are threefold:
+
+- Provide a realistic example of a distributed system that can be used to
+ demonstrate OpenTelemetry instrumentation and observability.
+- Build a base for vendors, tooling authors, and others to extend and
+ demonstrate their OpenTelemetry integrations.
+- Create a living example for OpenTelemetry contributors to use for testing new
+ versions of the API, SDK, and other components or enhancements.
+
+We've already made [huge
+progress](https://github.com/open-telemetry/opentelemetry-demo/blob/main/CHANGELOG.md),
+and development is ongoing. We hope to represent the full feature set of
+OpenTelemetry across its languages in the future.
+
+If you'd like to help (**which we would love**), check out our [contributing
+guidance](./CONTRIBUTING.md).
+
+If you'd like to extend this demo or maintain a fork of it, read our
+[fork guidance](https://opentelemetry.io/docs/demo/forking/).
+
+## Quick start
+
+You can be up and running with the demo in a few minutes. Check out the docs for
+your preferred deployment method:
+
+- [Docker](https://opentelemetry.io/docs/demo/docker_deployment/)
+- [Kubernetes](https://opentelemetry.io/docs/demo/kubernetes_deployment/)
+
+## Documentation
+
+For detailed documentation, see [Demo Documentation][docs]. If you're curious
+about a specific feature, the [docs landing page][docs] can point you in the
+right direction.
+
+## Demos featuring the Astronomy Shop
+
+We welcome any vendor to fork the project to demonstrate their services and
+adding a link below. The community is committed to maintaining the project and
+keeping it up to date for you.
+
+| | | |
+|-----------------------------------------|-----------------------------|----------------------------------------------------------------|
+| [AlibabaCloud LogService][AlibabaCloud] | [Elastic][Elastic] | [New Relic][NewRelic] |
+| [AppDynamics][AppDynamics] | [Google Cloud][GoogleCloud] | [OpenSearch][OpenSearch] |
+| [Aspecto][Aspecto] | [Grafana Labs][GrafanaLabs] | [Sentry][Sentry] |
+| [Axiom][Axiom] | [Guance][Guance] | [ServiceNow Cloud Observability][ServiceNowCloudObservability] |
+| [Axoflow][Axoflow] | [Helios][Helios] | [Splunk][Splunk] |
+| [Azure Data Explorer][Azure] | [Honeycomb.io][Honeycombio] | [Sumo Logic][SumoLogic] |
+| [Coralogix][Coralogix] | [Instana][Instana] | [TelemetryHub][TelemetryHub] |
+| [Dash0][Dash0] | [Kloudfuse][Kloudfuse] | [Teletrace][Teletrace] |
+| [Datadog][Datadog] | [Liatrio][Liatrio] | [Tracetest][Tracetest] |
+| [Dynatrace][Dynatrace] | [Logz.io][Logzio] | [Uptrace][Uptrace] |
+
+## Contributing
+
+To get involved with the project see our [CONTRIBUTING](CONTRIBUTING.md)
+documentation. Our [SIG Calls](CONTRIBUTING.md#join-a-sig-call) are every other
+Monday at 8:30 AM PST and anyone is welcome.
+
+## Project leadership
+
+[Maintainers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer)
+([@open-telemetry/demo-maintainers](https://github.com/orgs/open-telemetry/teams/demo-maintainers)):
+
+- [Juliano Costa](https://github.com/julianocosta89), Datadog
+- [Mikko Viitanen](https://github.com/mviitane), Dynatrace
+- [Pierre Tessier](https://github.com/puckpuck), Honeycomb
+
+[Approvers](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver)
+([@open-telemetry/demo-approvers](https://github.com/orgs/open-telemetry/teams/demo-approvers)):
+
+- [Cedric Ziel](https://github.com/cedricziel) Grafana Labs
+- [Penghan Wang](https://github.com/wph95), AppDynamics
+- [Reiley Yang](https://github.com/reyang), Microsoft
+- [Roger Coll](https://github.com/rogercoll), Elastic
+- [Ziqi Zhao](https://github.com/fatsheep9146), Alibaba
+
+Emeritus:
+
+- [Austin Parker](https://github.com/austinlparker)
+- [Carter Socha](https://github.com/cartersocha)
+- [Michael Maxwell](https://github.com/mic-max)
+- [Morgan McLean](https://github.com/mtwo)
+
+### Thanks to all the people who have contributed
+
+[![contributors](https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-demo)](https://github.com/open-telemetry/opentelemetry-demo/graphs/contributors)
+
+[docs]: https://opentelemetry.io/docs/demo/
+
+
+
+[AlibabaCloud]: https://github.com/aliyun-sls/opentelemetry-demo
+[AppDynamics]: https://www.appdynamics.com/blog/cloud/how-to-observe-opentelemetry-demo-app-in-appdynamics-cloud/
+[Aspecto]: https://github.com/aspecto-io/opentelemetry-demo
+[Axiom]: https://play.axiom.co/axiom-play-qf1k/dashboards/otel.traces.otel-demo-traces
+[Axoflow]: https://axoflow.com/opentelemetry-support-in-more-detail-in-axosyslog-and-syslog-ng/
+[Azure]: https://github.com/Azure/Azure-kusto-opentelemetry-demo
+[Coralogix]: https://coralogix.com/blog/configure-otel-demo-send-telemetry-data-coralogix
+[Dash0]: https://github.com/dash0hq/opentelemetry-demo
+[Datadog]: https://docs.datadoghq.com/opentelemetry/guide/otel_demo_to_datadog
+[Dynatrace]: https://www.dynatrace.com/news/blog/opentelemetry-demo-application-with-dynatrace/
+[Elastic]: https://github.com/elastic/opentelemetry-demo
+[GoogleCloud]: https://github.com/GoogleCloudPlatform/opentelemetry-demo
+[GrafanaLabs]: https://github.com/grafana/opentelemetry-demo
+[Guance]: https://github.com/GuanceCloud/opentelemetry-demo
+[Helios]: https://otelsandbox.gethelios.dev
+[Honeycombio]: https://github.com/honeycombio/opentelemetry-demo
+[Instana]: https://github.com/instana/opentelemetry-demo
+[Kloudfuse]: https://github.com/kloudfuse/opentelemetry-demo
+[Liatrio]: https://github.com/liatrio/opentelemetry-demo
+[Logzio]: https://logz.io/learn/how-to-run-opentelemetry-demo-with-logz-io/
+[NewRelic]: https://github.com/newrelic/opentelemetry-demo
+[OpenSearch]: https://github.com/opensearch-project/opentelemetry-demo
+[Sentry]: https://github.com/getsentry/opentelemetry-demo
+[ServiceNowCloudObservability]: https://docs.lightstep.com/otel/quick-start-operator#send-data-from-the-opentelemetry-demo
+[Splunk]: https://github.com/signalfx/opentelemetry-demo
+[SumoLogic]: https://www.sumologic.com/blog/common-opentelemetry-demo-application/
+[TelemetryHub]: https://github.com/TelemetryHub/opentelemetry-demo/tree/telemetryhub-backend
+[Teletrace]: https://github.com/teletrace/opentelemetry-demo
+[Tracetest]: https://github.com/kubeshop/opentelemetry-demo
+[Uptrace]: https://github.com/uptrace/uptrace/tree/master/example/opentelemetry-demo
diff --git a/ansible/README.md b/ansible/README.md
new file mode 100644
index 0000000000..e0ff92bbac
--- /dev/null
+++ b/ansible/README.md
@@ -0,0 +1,5 @@
+### ANSIBLE
+To execute the ansible files from run in this directory (ansible):
+```shell
+ansible-playbook -i hosts.yaml main.yaml
+```
\ No newline at end of file
diff --git a/ansible/hosts.yaml b/ansible/hosts.yaml
new file mode 100644
index 0000000000..ece60a1e5e
--- /dev/null
+++ b/ansible/hosts.yaml
@@ -0,0 +1,4 @@
+all:
+ hosts:
+ localhost:
+ ansible_connection: local
\ No newline at end of file
diff --git a/ansible/main.yaml b/ansible/main.yaml
new file mode 100644
index 0000000000..af5d19e7a4
--- /dev/null
+++ b/ansible/main.yaml
@@ -0,0 +1,145 @@
+---
+- name: Deploy OpenTelemetry Demo
+ hosts: all
+ become: true
+ vars:
+ demo_version: "1.11.1"
+ network_name: "opentelemetry-demo"
+ state: "started"
+ restart_policy: "unless-stopped"
+ log_driver: "json-file"
+ log_options_max_size: "5m"
+ log_options_max_file: "2"
+ flagd_host: "flagd"
+ flagd_port: "8013"
+ otel_collector_host: "otelcol"
+ otel_collector_port_grpc: "4317"
+ otel_collector_port_http: "4318"
+ envoy_port: "8080"
+ pre_tasks:
+ # This is not working on every docker environment, and for the installation it is not essential
+ #- name: Ensure Docker is installed
+ # apt:
+ # name: docker.io
+ # state: present
+ # become: true
+
+ - name: Ensure default network is created
+ docker_network:
+ name: opentelemetry-demo
+ driver: bridge
+
+ roles:
+ - role: accountingservice
+ become: true
+ - role: adservice
+ become: true
+ - role: cartservice
+ become: true
+ - role: checkoutservice
+ become: true
+ - role: currencyservice
+ become: true
+ - role: emailservice
+ become: true
+ - role: frauddetectionservice
+ become: true
+ - role: flagd
+ become: true
+ - role: frontend
+ become: true
+ - role: frontendproxy
+ become: true
+ - role: grafana
+ become: true
+ - role: imageprovider
+ become: true
+ - role: jaeger
+ become: true
+ - role: kafka
+ become: true
+ - role: loadgenerator
+ become: true
+ - role: mongo
+ become: true
+ - role: opensearch
+ become: true
+ - role: otelcol
+ become: true
+ - role: paymentservice
+ become: true
+ - role: productcatalogservice
+ become: true
+ - role: prometheus
+ become: true
+ - role: quoteservice
+ become: true
+ - role: recommendationservice
+ become: true
+ - role: shippingservice
+ become: true
+ - role: valkeycart
+ become: true
+
+ post_tasks:
+ - name: Ensure services are started
+ community.general.launchd:
+ # TODO FIX should be {{ item }} but this cannot be properly parsed yet
+ name: "item"
+ state: "{{ state }}"
+ loop:
+ - accountingservice
+ - adservice
+ - cartservice
+ - checkoutservice
+ - emailservice
+ - flagd
+ - frauddetectionserice
+ - frontend
+ - frontendproxy
+ - grafana
+ - imageprovider
+ - jaeger
+ - kafka
+ - loadgenerator
+ - mongo
+ - opensearch
+ - otelcol
+ - paymentservice
+ - productcatalogservice
+ - prometheus
+ - quoteservice
+ - recommendationservice
+ - shippingservice
+ - valkeycart
+
+ - name: Ensure services are enabled to start at boot
+ community.general.launchd:
+ # TODO FIX should be {{ item }} but this cannot be properly parsed yet
+ name: "item"
+ enabled: yes
+ loop:
+ - accountingservice
+ - adservice
+ - cartservice
+ - checkoutservice
+ - emailservice
+ - flagd
+ - frauddetectionserice
+ - frontend
+ - frontendproxy
+ - grafana
+ - imageprovider
+ - jaeger
+ - kafka
+ - loadgenerator
+ - mongo
+ - opensearch
+ - otelcol
+ - paymentservice
+ - productcatalogservice
+ - prometheus
+ - quoteservice
+ - recommendationservice
+ - shippingservice
+ - valkeycart
diff --git a/ansible/roles/accountingservice/defaults/main.yaml b/ansible/roles/accountingservice/defaults/main.yaml
new file mode 100644
index 0000000000..17015dfd7e
--- /dev/null
+++ b/ansible/roles/accountingservice/defaults/main.yaml
@@ -0,0 +1,5 @@
+service_name: "accountingservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-accountingservice"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "120M"
+kafkaservice_addr: "kafka:9092"
\ No newline at end of file
diff --git a/ansible/roles/accountingservice/meta/main.yaml b/ansible/roles/accountingservice/meta/main.yaml
new file mode 100644
index 0000000000..ffb62d3178
--- /dev/null
+++ b/ansible/roles/accountingservice/meta/main.yaml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - role: kafka
+ - role: otelcol
\ No newline at end of file
diff --git a/ansible/roles/accountingservice/tasks/main.yaml b/ansible/roles/accountingservice/tasks/main.yaml
new file mode 100644
index 0000000000..9e4a9e382d
--- /dev/null
+++ b/ansible/roles/accountingservice/tasks/main.yaml
@@ -0,0 +1,27 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_http }}"
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "{{ otlp_metrics_temporality_preference }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ KAFKA_SERVICE_ADDR: "{{ kafkaservice_addr }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/adservice/defaults/main.yaml b/ansible/roles/adservice/defaults/main.yaml
new file mode 100644
index 0000000000..0d1ce71540
--- /dev/null
+++ b/ansible/roles/adservice/defaults/main.yaml
@@ -0,0 +1,6 @@
+service_name: "adservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-adservice"
+ports: "9555"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "300M"
+logs_exporter: "otlp"
diff --git a/ansible/roles/adservice/meta/main.yaml b/ansible/roles/adservice/meta/main.yaml
new file mode 100644
index 0000000000..40f8df1485
--- /dev/null
+++ b/ansible/roles/adservice/meta/main.yaml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - role: otelcol
+ - role: flagd
\ No newline at end of file
diff --git a/ansible/roles/adservice/tasks/main.yaml b/ansible/roles/adservice/tasks/main.yaml
new file mode 100644
index 0000000000..60fd565229
--- /dev/null
+++ b/ansible/roles/adservice/tasks/main.yaml
@@ -0,0 +1,31 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_http }}"
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "{{ otlp_metrics_temporality_preference }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ OTEL_LOGS_EXPORTER: "{{ logs_exporter }}"
+ AD_SERVICE_PORT: "{{ ports }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ ports: "{{ ports }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/cartservice/defaults/main.yaml b/ansible/roles/cartservice/defaults/main.yaml
new file mode 100644
index 0000000000..68c7a05e55
--- /dev/null
+++ b/ansible/roles/cartservice/defaults/main.yaml
@@ -0,0 +1,6 @@
+service_name: "cartservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-cartservice"
+ports: "7070"
+memory_limit: "160M"
+valkey_addr: "valkeycart:6379"
+aspnetcore_urls: "http://*:7070"
\ No newline at end of file
diff --git a/ansible/roles/cartservice/meta/main.yaml b/ansible/roles/cartservice/meta/main.yaml
new file mode 100644
index 0000000000..c9f8762a7a
--- /dev/null
+++ b/ansible/roles/cartservice/meta/main.yaml
@@ -0,0 +1,5 @@
+---
+dependencies:
+ - role: otelcol
+ - role: flagd
+ - role: valkeycart
\ No newline at end of file
diff --git a/ansible/roles/cartservice/tasks/main.yaml b/ansible/roles/cartservice/tasks/main.yaml
new file mode 100644
index 0000000000..7e481c32a1
--- /dev/null
+++ b/ansible/roles/cartservice/tasks/main.yaml
@@ -0,0 +1,32 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_grpc }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ CART_SERVICE_PORT: "{{ ports }}"
+ VALKEY_ADDR: "{{ valkey_addr }}"
+ REDIS_ADDR: "{{ valkey_addr }}"
+ ASPNETCORE_URLS: "{{ aspnetcore_urls }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ ports: "{{ ports }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/checkoutservice/defaults/main.yaml b/ansible/roles/checkoutservice/defaults/main.yaml
new file mode 100644
index 0000000000..ac3703eb63
--- /dev/null
+++ b/ansible/roles/checkoutservice/defaults/main.yaml
@@ -0,0 +1,13 @@
+service_name: "checkoutservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-checkoutservice"
+ports: "5050"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "120M"
+logs_exporter: "otlp"
+cartservice_addr: "cartservice:7070"
+currencyservice_addr: "currencyservice:7001"
+emailservice_addr: "http://emailservice:6060"
+paymentservice_addr: "paymentservice:50051"
+productcatalogservice_addr: "productcatalogservice:3550"
+shippingservice_addr: "shippingservice:50050"
+kafkaservice_addr: "kafka:9092"
\ No newline at end of file
diff --git a/ansible/roles/checkoutservice/meta/main.yaml b/ansible/roles/checkoutservice/meta/main.yaml
new file mode 100644
index 0000000000..f76e5e61db
--- /dev/null
+++ b/ansible/roles/checkoutservice/meta/main.yaml
@@ -0,0 +1,11 @@
+---
+dependencies:
+ - role: cartservice
+ - role: currencyservice
+ - role: emailservice
+ - role: paymentservice
+ - role: productcatalogservice
+ - role: shippingservice
+ - role: otelcol
+ - role: kafka
+ - role: flagd
\ No newline at end of file
diff --git a/ansible/roles/checkoutservice/tasks/main.yaml b/ansible/roles/checkoutservice/tasks/main.yaml
new file mode 100644
index 0000000000..2f38a1532d
--- /dev/null
+++ b/ansible/roles/checkoutservice/tasks/main.yaml
@@ -0,0 +1,39 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_grpc }}"
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "{{ otlp_metrics_temporality_preference }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ OTEL_LOGS_EXPORTER: "{{ logs_exporter }}"
+ CHECKOUT_SERVICE_PORT: "{{ ports }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ CART_SERVICE_ADDR: "{{ cartservice_addr }}"
+ CURRENCY_SERVICE_ADDR: "{{ currencyservice_addr }}"
+ EMAIL_SERVICE_ADDR: "{{ emailservice_addr }}"
+ PAYMENT_SERVICE_ADDR: "{{ paymentservice_addr }}"
+ PRODUCT_CATALOG_SERVICE_ADDR: "{{ productcatalogservice_addr }}"
+ SHIPPING_SERVICE_ADDR: "{{ shippingservice_addr }}"
+ KAFKA_SERVICE_ADDR: "{{ kafkaservice_addr }}"
+
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ ports: "{{ ports }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/currencyservice/defaults/main.yaml b/ansible/roles/currencyservice/defaults/main.yaml
new file mode 100644
index 0000000000..0979808e14
--- /dev/null
+++ b/ansible/roles/currencyservice/defaults/main.yaml
@@ -0,0 +1,7 @@
+service_name: "currencyservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-currencyservice"
+ports: "7001"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "20M"
+
+logs_exporter: "otlp"
diff --git a/ansible/roles/currencyservice/meta/main.yaml b/ansible/roles/currencyservice/meta/main.yaml
new file mode 100644
index 0000000000..9ef25e04db
--- /dev/null
+++ b/ansible/roles/currencyservice/meta/main.yaml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - role: otelcol
\ No newline at end of file
diff --git a/ansible/roles/currencyservice/tasks/main.yaml b/ansible/roles/currencyservice/tasks/main.yaml
new file mode 100644
index 0000000000..e4b75e7fde
--- /dev/null
+++ b/ansible/roles/currencyservice/tasks/main.yaml
@@ -0,0 +1,28 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_grpc }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ VERSION: "{{ demo_version }}"
+ CURRENCY_SERVICE_PORT: "{{ ports }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ ports: "{{ ports }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/emailservice/defaults/main.yaml b/ansible/roles/emailservice/defaults/main.yaml
new file mode 100644
index 0000000000..7d3ce913b3
--- /dev/null
+++ b/ansible/roles/emailservice/defaults/main.yaml
@@ -0,0 +1,6 @@
+service_name: "emailservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-emailservice"
+ports: "6060"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "100M"
+app_env: "production"
\ No newline at end of file
diff --git a/ansible/roles/emailservice/meta/main.yaml b/ansible/roles/emailservice/meta/main.yaml
new file mode 100644
index 0000000000..9ef25e04db
--- /dev/null
+++ b/ansible/roles/emailservice/meta/main.yaml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - role: otelcol
\ No newline at end of file
diff --git a/ansible/roles/emailservice/tasks/main.yaml b/ansible/roles/emailservice/tasks/main.yaml
new file mode 100644
index 0000000000..07a49acbff
--- /dev/null
+++ b/ansible/roles/emailservice/tasks/main.yaml
@@ -0,0 +1,28 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}"#:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_http }}/v1/traces"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ EMAIL_SERVICE_PORT: "{{ ports }}"
+ APP_ENV: "{{ app_env }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ ports: "{{ ports }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/flagd/defaults/main.yaml b/ansible/roles/flagd/defaults/main.yaml
new file mode 100644
index 0000000000..f547162375
--- /dev/null
+++ b/ansible/roles/flagd/defaults/main.yaml
@@ -0,0 +1,7 @@
+service_name: "flagd"
+image_name: "ghcr.io/open-feature/flagd:v0.11.2"
+ports: "8013"
+memory_limit: "50M"
+command: '["start", "--uri", "file:./etc/flagd/demo.flagd.json"]'
+volumes:
+ - ./roles/flagd/files/demo.flagd.json:/etc/flagd/demo.flagd.json
\ No newline at end of file
diff --git a/ansible/roles/flagd/files/demo.flagd.json b/ansible/roles/flagd/files/demo.flagd.json
new file mode 100644
index 0000000000..2d46891ef2
--- /dev/null
+++ b/ansible/roles/flagd/files/demo.flagd.json
@@ -0,0 +1,105 @@
+{
+ "$schema": "https://flagd.dev/schema/v0/flags.json",
+ "flags": {
+ "productCatalogFailure": {
+ "description": "Fail product catalog service on a specific product",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "recommendationServiceCacheFailure": {
+ "description": "Fail recommendation service cache",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "adServiceManualGc": {
+ "description": "Triggers full manual garbage collections in the ad service",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "adServiceHighCpu": {
+ "description": "Triggers high cpu load in the ad service",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "adServiceFailure": {
+ "description": "Fail ad service",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "kafkaQueueProblems": {
+ "description": "Overloads Kafka queue while simultaneously introducing a consumer side delay leading to a lag spike",
+ "state": "ENABLED",
+ "variants": {
+ "on": 100,
+ "off": 0
+ },
+ "defaultVariant": "off"
+ },
+ "cartServiceFailure": {
+ "description": "Fail cart service",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "paymentServiceFailure": {
+ "description": "Fail payment service charge requests",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "paymentServiceUnreachable": {
+ "description": "Payment service is unavailable",
+ "state": "ENABLED",
+ "variants": {
+ "on": true,
+ "off": false
+ },
+ "defaultVariant": "off"
+ },
+ "loadgeneratorFloodHomepage": {
+ "description": "Flood the frontend with a large amount of requests.",
+ "state": "ENABLED",
+ "variants": {
+ "on": 100,
+ "off": 0
+ },
+ "defaultVariant": "off"
+ },
+ "imageSlowLoad": {
+ "description": "slow loading images in the frontend",
+ "state": "ENABLED",
+ "variants": {
+ "10sec": 10000,
+ "5sec": 5000,
+ "off": 0
+ },
+ "defaultVariant": "off"
+ }
+ }
+}
diff --git a/ansible/roles/flagd/tasks/main.yaml b/ansible/roles/flagd/tasks/main.yaml
new file mode 100644
index 0000000000..93a8e7741a
--- /dev/null
+++ b/ansible/roles/flagd/tasks/main.yaml
@@ -0,0 +1,28 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ FLAGD_OTEL_COLLECTOR_URI: "{{ otel_collector_host }}:{{ otel_collector_port_grpc }}"
+ FLAGD_METRICS_EXPORTER: "otel"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ memory: "{{ memory_limit }}"
+ ports: "{{ ports }}"
+ state: "{{ state }}"
+ command: "{{ command }}"
+ volumes: "{{ volumes }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/frauddetectionservice/defaults/main.yaml b/ansible/roles/frauddetectionservice/defaults/main.yaml
new file mode 100644
index 0000000000..9ef92a7d3f
--- /dev/null
+++ b/ansible/roles/frauddetectionservice/defaults/main.yaml
@@ -0,0 +1,6 @@
+service_name: "frauddetectionservice"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-frauddetectionservice"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "300M"
+kafkaservice_addr: "kafka:9092"
+otlp_experimental_features: "true"
\ No newline at end of file
diff --git a/ansible/roles/frauddetectionservice/meta/main.yaml b/ansible/roles/frauddetectionservice/meta/main.yaml
new file mode 100644
index 0000000000..81fa803285
--- /dev/null
+++ b/ansible/roles/frauddetectionservice/meta/main.yaml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - role: otelcol
+ - role: kafka
\ No newline at end of file
diff --git a/ansible/roles/frauddetectionservice/tasks/main.yaml b/ansible/roles/frauddetectionservice/tasks/main.yaml
new file mode 100644
index 0000000000..d11f741c24
--- /dev/null
+++ b/ansible/roles/frauddetectionservice/tasks/main.yaml
@@ -0,0 +1,31 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_http }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ KAFKA_SERVICE_ADDR: "{{ kafkaservice_addr }}"
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "{{ otlp_metrics_temporality_preference }}"
+ OTEL_INSTRUMENTATION_KAFKA_EXPERIMENTAL_SPAN_ATTRIBUTES: "{{ otlp_experimental_features }}"
+ OTEL_INSTRUMENTATION_MESSAGING_EXPERIMENTAL_RECEIVE_TELEMETRY_ENABLED: "{{ otlp_experimental_features }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ state: "{{ state }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/frontend/defaults/main.yaml b/ansible/roles/frontend/defaults/main.yaml
new file mode 100644
index 0000000000..481eab9268
--- /dev/null
+++ b/ansible/roles/frontend/defaults/main.yaml
@@ -0,0 +1,16 @@
+service_name: "frontend"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-frontend"
+ports: "8080"
+otlp_metrics_temporality_preference : "cumulative"
+memory_limit: "250M"
+kafkaservice_addr: "kafka:9092"
+adservice_addr: "adservice:9555"
+cartservice_addr: "cartservice:7070"
+checkoutservice_addr: "checkoutservice:5050"
+currencyservice_addr: "currencyservice:7001"
+productcatalogservice_addr: "productcatalogservice:3550"
+recommendationservice_addr: "recommendationservice:9001"
+shippingservice_addr: "shippingservice:50050"
+env_platform: "local"
+otlp_exporter_traces_endpoint: "http://otelcol:8080/otlp-http/v1/traces"
+web_otel_service_name: "frontend-web"
\ No newline at end of file
diff --git a/ansible/roles/frontend/meta/main.yaml b/ansible/roles/frontend/meta/main.yaml
new file mode 100644
index 0000000000..cae13714bb
--- /dev/null
+++ b/ansible/roles/frontend/meta/main.yaml
@@ -0,0 +1,13 @@
+---
+dependencies:
+ - role: adservice
+ - role: cartservice
+ - role: checkoutservice
+ - role: currencyservice
+ - role: productcatalogservice
+ - role: quoteservice
+ - role: recommendationservice
+ - role: shippingservice
+ - role: otelcol
+ - role: imageprovider
+ - role: flagd
\ No newline at end of file
diff --git a/ansible/roles/frontend/tasks/main.yaml b/ansible/roles/frontend/tasks/main.yaml
new file mode 100644
index 0000000000..2a04687d9b
--- /dev/null
+++ b/ansible/roles/frontend/tasks/main.yaml
@@ -0,0 +1,45 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://{{ otel_collector_host }}:{{ otel_collector_port_grpc }}"
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ VERSION: "{{ demo_version }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ KAFKA_SERVICE_ADDR: "{{ kafkaservice_addr }}"
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: "{{ otlp_metrics_temporality_preference }}"
+ PORT: "{{ ports }}"
+ FRONTEND_ADDR: "{{ service_name }}:{{ ports }}"
+ AD_SERVICE_ADDR: "{{ adservice_addr }}"
+ CART_SERVICE_ADDR: "{{ cartservice_addr }}"
+ CHECKOUT_SERVICE_ADDR: "{{ checkoutservice_addr }}"
+ CURRENCY_SERVICE_ADDR: "{{ currencyservice_addr }}"
+ PRODUCT_CATALOG_SERVICE_ADDR: "{{ productcatalogservice_addr }}"
+ RECOMMENDATION_SERVICE_ADDR: "{{ recommendationservice_addr }}"
+ SHIPPING_SERVICE_ADDR: "{{ shippingservice_addr }}"
+ ENV_PLATFORM: "{{ env_platform }}"
+ PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "{{ otlp_exporter_traces_endpoint }}"
+ WEB_OTEL_SERVICE_NAME: "{{ web_otel_service_name }}"
+ otel_collector_host: "{{ otel_collector_host }}"
+
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ ports: "{{ ports }}"
+ state: "{{ state }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
+ log_options:
+ max-size: "{{ log_options_max_size }}"
+ max-file: "{{ log_options_max_file }}"
+ tag: "{{ service_name }}"
\ No newline at end of file
diff --git a/ansible/roles/frontendproxy/defaults/main.yaml b/ansible/roles/frontendproxy/defaults/main.yaml
new file mode 100644
index 0000000000..dff08a6d21
--- /dev/null
+++ b/ansible/roles/frontendproxy/defaults/main.yaml
@@ -0,0 +1,16 @@
+service_name: "frontendproxy"
+image_name: "ghcr.io/open-telemetry/demo:1.11.1-frontendproxy"
+ports:
+ - "10000:10000"
+ - "8080:8080"
+memory_limit: "50M"
+locust_web_host: "loadgenerator"
+locust_web_port: "8089"
+jaeger_host: "jaeger"
+jaeger_port: "16686"
+imageprovider_host: "imageprovider"
+imageprovider_port: "8081"
+grafana_host: "grafana"
+grafana_port: "3000"
+frontend_host: "frontend"
+frontend_port: "8080"
\ No newline at end of file
diff --git a/ansible/roles/frontendproxy/meta/main.yaml b/ansible/roles/frontendproxy/meta/main.yaml
new file mode 100644
index 0000000000..719fed4a58
--- /dev/null
+++ b/ansible/roles/frontendproxy/meta/main.yaml
@@ -0,0 +1,6 @@
+---
+dependencies:
+ - role: frontend
+ - role: jaeger
+ - role: loadgenerator
+ - role: grafana
diff --git a/ansible/roles/frontendproxy/tasks/main.yaml b/ansible/roles/frontendproxy/tasks/main.yaml
new file mode 100644
index 0000000000..fdf1c92644
--- /dev/null
+++ b/ansible/roles/frontendproxy/tasks/main.yaml
@@ -0,0 +1,37 @@
+---
+- name: Pull the latest Docker image
+ docker_image:
+ name: "{{ image_name }}:{{ demo_version }}-{{ service_name }}"
+ source: pull
+
+- name: Deploy Service
+ docker_container:
+ name: "{{ service_name }}"
+ image: "{{ image_name }}"
+ env:
+ OTEL_RESOURCE_ATTRIBUTES: "service.name={{ service_name }},service.namespace=opentelemetry-demo,service.version={{ demo_version }}"
+ OTEL_SERVICE_NAME: "{{ service_name }}"
+ OTEL_COLLECTOR_HOST: "{{ otel_collector_host }}"
+ FLAGD_HOST: "{{ flagd_host }}"
+ FLAGD_PORT: "{{ flagd_port }}"
+ OTEL_COLLECTOR_PORT_GRPC: "{{ otel_collector_port_grpc }}"
+ OTEL_COLLECTOR_PORT_HTTP: "{{ otel_collector_port_http }}"
+ FRONTEND_HOST: "{{ frontend_host }}"
+ FRONTEND_PORT: "{{ frontend_port }}"
+ GRAFANA_SERVICE_HOST: "{{ grafana_host }}"
+ GRAFANA_SERVICE_PORT: "{{ grafana_port }}"
+ IMAGE_PROVIDER_HOST: "{{ imageprovider_host }}"
+ IMAGE_PROVIDER_PORT: "{{ imageprovider_port }}"
+ JAEGER_SERVICE_HOST: "{{ jaeger_host }}"
+ JAEGER_SERVICE_PORT: "{{ jaeger_port }}"
+ LOCUST_WEB_HOST: "{{ locust_web_host }}"
+ LOCUST_WEB_PORT: "{{ locust_web_port }}"
+ ENVOY_PORT: "{{ envoy_port }}"
+ restart_policy: "{{ restart_policy }}"
+ memory: "{{ memory_limit }}"
+ ports: "{{ ports }}"
+ state: "{{ state }}"
+ network_mode: "{{ network_name }}"
+ networks:
+ - name: "{{ network_name }}"
+ log_driver: "{{ log_driver }}"
\ No newline at end of file
diff --git a/ansible/roles/grafana/defaults/main.yaml b/ansible/roles/grafana/defaults/main.yaml
new file mode 100644
index 0000000000..de455187a2
--- /dev/null
+++ b/ansible/roles/grafana/defaults/main.yaml
@@ -0,0 +1,7 @@
+service_name: "grafana"
+image_name: "grafana/grafana:11.2.0"
+memory_limit: "100M"
+ports: "3000"
+volumes:
+ - ./roles/grafana/files/grafana.ini:/etc/grafana/grafana.ini
+ - ./roles/grafana/files/provisioning/:/etc/grafana/provisioning/
\ No newline at end of file
diff --git a/ansible/roles/grafana/files/grafana.ini b/ansible/roles/grafana/files/grafana.ini
new file mode 100644
index 0000000000..2443041290
--- /dev/null
+++ b/ansible/roles/grafana/files/grafana.ini
@@ -0,0 +1,1172 @@
+
+
+##################### Grafana Configuration Example #####################
+#
+# Everything has defaults so you only need to uncomment things you want to
+# change
+
+# possible values : production, development
+;app_mode = production
+
+# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
+;instance_name = ${HOSTNAME}
+
+# force migration will run migrations that might cause dataloss
+;force_migration = false
+
+#################################### Paths ####################################
+[paths]
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
+;data = /var/lib/grafana
+
+# Temporary files in `data` directory older than given duration will be removed
+;temp_data_lifetime = 24h
+
+# Directory where grafana can store logs
+;logs = /var/log/grafana
+
+# Directory where grafana will automatically scan and look for plugins
+;plugins = /var/lib/grafana/plugins
+
+# folder that contains provisioning config files that grafana will apply on startup and while running.
+provisioning = /etc/grafana/provisioning
+
+#################################### Server ####################################
+[server]
+# Protocol (http, https, h2, socket)
+protocol = http
+
+# The ip address to bind to, empty will bind to all interfaces
+;http_addr =
+
+# The http port to use
+http_port = 3000
+
+# The public facing domain name used to access grafana from a browser
+domain = localhost
+
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+;enforce_domain = false
+
+# The full public facing url you use in browser, used for redirects and emails
+# If you use reverse proxy and sub path specify full url (with sub path)
+root_url = %(protocol)s://%(domain)s/grafana/
+
+# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons.
+serve_from_sub_path = true
+
+# Log web requests
+;router_logging = false
+
+# the path relative working path
+;static_root_path = public
+
+# enable gzip
+;enable_gzip = false
+
+# https certs & key file
+;cert_file =
+;cert_key =
+
+# Unix socket path
+;socket =
+
+# CDN Url
+;cdn_url =
+
+# Sets the maximum time using a duration format (5s/5m/5ms) before timing out read of an incoming request and closing idle connections.
+# `0` means there is no timeout for reading the request.
+;read_timeout = 0
+
+#################################### Database ####################################
+[database]
+# You can configure the database connection by specifying type, host, name, user and password
+# as separate properties or as on string using the url properties.
+
+# Either "mysql", "postgres" or "sqlite3", it's your choice
+;type = sqlite3
+;host = 127.0.0.1:3306
+;name = grafana
+;user = root
+# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
+;password =
+
+# Use either URL or the previous fields to configure the database
+# Example: mysql://user:secret@host:port/database
+;url =
+
+# For "postgres" only, either "disable", "require" or "verify-full"
+;ssl_mode = disable
+
+# Database drivers may support different transaction isolation levels.
+# Currently, only "mysql" driver supports isolation levels.
+# If the value is empty - driver's default isolation level is applied.
+# For "mysql" use "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE".
+;isolation_level =
+
+;ca_cert_path =
+;client_key_path =
+;client_cert_path =
+;server_cert_name =
+
+# For "sqlite3" only, path relative to data_path setting
+;path = grafana.db
+
+# Max idle conn setting default is 2
+;max_idle_conn = 2
+
+# Max conn setting default is 0 (mean not set)
+;max_open_conn =
+
+# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours)
+;conn_max_lifetime = 14400
+
+# Set to true to log the sql calls and execution times.
+;log_queries =
+
+# For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared)
+;cache_mode = private
+
+# For "mysql" only if lockingMigration feature toggle is set. How many seconds to wait before failing to lock the database for the migrations, default is 0.
+;locking_attempt_timeout_sec = 0
+
+################################### Data sources #########################
+[datasources]
+# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API.
+;datasource_limit = 5000
+
+#################################### Cache server #############################
+[remote_cache]
+# Either "redis", "memcached" or "database" default is "database"
+;type = database
+
+# cache connectionstring options
+# database: will use Grafana primary database.
+# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=0,ssl=false`. Only addr is required. ssl may be 'true', 'false', or 'insecure'.
+# memcache: 127.0.0.1:11211
+;connstr =
+
+#################################### Data proxy ###########################
+[dataproxy]
+
+# This enables data proxy logging, default is false
+;logging = false
+
+# How long the data proxy waits to read the headers of the response before timing out, default is 30 seconds.
+# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set.
+;timeout = 30
+
+# How long the data proxy waits to establish a TCP connection before timing out, default is 10 seconds.
+;dialTimeout = 10
+
+# How many seconds the data proxy waits before sending a keepalive probe request.
+;keep_alive_seconds = 30
+
+# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
+;tls_handshake_timeout_seconds = 10
+
+# How many seconds the data proxy will wait for a server's first response headers after
+# fully writing the request headers if the request has an "Expect: 100-continue"
+# header. A value of 0 will result in the body being sent immediately, without
+# waiting for the server to approve.
+;expect_continue_timeout_seconds = 1
+
+# Optionally limits the total number of connections per host, including connections in the dialing,
+# active, and idle states. On limit violation, dials will block.
+# A value of zero (0) means no limit.
+;max_conns_per_host = 0
+
+# The maximum number of idle connections that Grafana will keep alive.
+;max_idle_connections = 100
+
+# How many seconds the data proxy keeps an idle connection open before timing out.
+;idle_conn_timeout_seconds = 90
+
+# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
+;send_user_header = false
+
+# Limit the amount of bytes that will be read/accepted from responses of outgoing HTTP requests.
+;response_limit = 0
+
+# Limits the number of rows that Grafana will process from SQL data sources.
+;row_limit = 1000000
+
+#################################### Analytics ####################################
+[analytics]
+# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
+# No ip addresses are being tracked, only simple counters to track
+# running instances, dashboard and error counts. It is very helpful to us.
+# Change this option to false to disable reporting.
+;reporting_enabled = true
+
+# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
+;reporting_distributor = grafana-labs
+
+# Set to false to disable all checks to https://grafana.com
+# for new versions of grafana. The check is used
+# in some UI views to notify that a grafana update exists.
+# This option does not cause any auto updates, nor send any information
+# only a GET request to https://raw.githubusercontent.com/grafana/grafana/main/latest.json to get the latest version.
+;check_for_updates = true
+
+# Set to false to disable all checks to https://grafana.com
+# for new versions of plugins. The check is used
+# in some UI views to notify that a plugin update exists.
+# This option does not cause any auto updates, nor send any information
+# only a GET request to https://grafana.com to get the latest versions.
+;check_for_plugin_updates = true
+
+# Google Analytics universal tracking code, only enabled if you specify an id here
+;google_analytics_ua_id =
+
+# Google Tag Manager ID, only enabled if you specify an id here
+;google_tag_manager_id =
+
+# Rudderstack write key, enabled only if rudderstack_data_plane_url is also set
+;rudderstack_write_key =
+
+# Rudderstack data plane url, enabled only if rudderstack_write_key is also set
+;rudderstack_data_plane_url =
+
+# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
+;rudderstack_sdk_url =
+
+# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
+;rudderstack_config_url =
+
+# Controls if the UI contains any links to user feedback forms
+;feedback_links_enabled = true
+
+#################################### Security ####################################
+[security]
+# disable creation of admin user on first start of grafana
+;disable_initial_admin_creation = false
+
+# default admin user, created on startup
+;admin_user = admin
+
+# default admin password, can be changed before first start of grafana, or in profile settings
+;admin_password = admin
+
+# used for signing
+;secret_key = SW2YcwTIb9zpOOhoPsMm
+
+# current key provider used for envelope encryption, default to static value specified by secret_key
+;encryption_provider = secretKey.v1
+
+# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
+;available_encryption_providers =
+
+# disable gravatar profile images
+;disable_gravatar = false
+
+# data source proxy whitelist (ip_or_domain:port separated by spaces)
+;data_source_proxy_whitelist =
+
+# disable protection against brute force login attempts
+;disable_brute_force_login_protection = false
+
+# set to true if you host Grafana behind HTTPS. default is false.
+;cookie_secure = false
+
+# set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled"
+;cookie_samesite = lax
+
+# set to true if you want to allow browsers to render Grafana in a ,