Full Code of mchmarny/dapr-demos for AI

master cc29106fb457 cached
291 files
1.1 MB
318.3k tokens
126 symbols
1 requests
Download .txt
Showing preview only (1,213K chars total). Download the full file or copy to clipboard to get everything.
Repository: mchmarny/dapr-demos
Branch: master
Commit: cc29106fb457
Files: 291
Total size: 1.1 MB

Directory structure:
gitextract_3z6jna8z/

├── .gitignore
├── LICENSE
├── README.md
├── apim-gateway/
│   ├── README.md
│   ├── apim/
│   │   ├── api.yaml
│   │   ├── policy-all.json
│   │   ├── policy-echo.json
│   │   ├── policy-message.json
│   │   └── policy-save.json
│   └── k8s/
│       ├── binding.yaml
│       ├── echo-service.yaml
│       ├── event-subscriber.yaml
│       ├── gateway.yaml
│       └── pubsub.yaml
├── autoscaling-on-queue/
│   ├── README.md
│   ├── deployment/
│   │   ├── kafka-client.yaml
│   │   ├── kafka-pubsub.yaml
│   │   ├── keda-2.0.0-beta.yaml
│   │   ├── producer.yaml
│   │   ├── subscriber-scaler.yaml
│   │   └── subscriber.yaml
│   ├── producer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── subscriber/
│       ├── Dockerfile
│       ├── Makefile
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── component-api/
│   ├── README.md
│   ├── config/
│   │   ├── email.yaml
│   │   ├── state.yaml
│   │   └── twitter.yaml
│   └── sample/
│       ├── email.json
│       └── twitter.json
├── cron-binding/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   └── cron.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── dapr-aci/
│   ├── README.md
│   ├── components/
│   │   ├── pubsub.yaml
│   │   └── state.yaml
│   ├── deployment/
│   │   └── app.yaml
│   └── src/
│       ├── Dockerfile
│       ├── Makefile
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── dapr-api-on-aci/
│   ├── README.md
│   └── email.yaml
├── daprized-ingress/
│   ├── README.md
│   └── config/
│       ├── ingress-annotations.yaml
│       ├── ingress-config.yaml
│       ├── ingress.yaml
│       └── namespace.yml
├── fan-out/
│   ├── README.md
│   ├── grpc-echo-service/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── deployment.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── http-format-converter/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── source-pubsub.yaml
│   │   │   └── target-binding.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── components.yaml
│   │   │   └── deployment.yaml
│   │   └── main.go
│   ├── queue-event-consumer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   └── source-pabusb.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   ├── queue-event-producer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   └── target-pabusb.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   ├── queue-format-converter/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── kafka.yaml
│   │   │   ├── source-pabusb.yaml
│   │   │   └── target-pubsub.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   └── service-format-converter/
│       ├── Dockerfile
│       ├── Makefile
│       ├── config/
│       │   └── source-pubsub.yaml
│       ├── go.mod
│       ├── go.sum
│       ├── k8s/
│       │   ├── components.yaml
│       │   └── deployment.yaml
│       └── main.go
├── grpc-echo-service/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── deployment/
│   │   ├── app.yaml
│   │   └── space.yaml
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── grpc-event-subscriber/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   └── pubsub.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── hardened/
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   ├── pubsub.yaml
│   │   └── state.yaml
│   ├── deployment/
│   │   ├── hardened/
│   │   │   ├── app1.yaml
│   │   │   ├── app2.yaml
│   │   │   ├── app3.yaml
│   │   │   ├── pubsub.yaml
│   │   │   └── state.yaml
│   │   ├── namespace/
│   │   │   ├── ns.yaml
│   │   │   ├── role.yaml
│   │   │   └── trace.yaml
│   │   └── simple/
│   │       ├── app1.yaml
│   │       ├── app2.yaml
│   │       ├── app3.yaml
│   │       ├── pubsub.yaml
│   │       └── state.yaml
│   └── src/
│       ├── app1/
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── go.mod
│       │   ├── go.sum
│       │   └── main.go
│       ├── app2/
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── go.mod
│       │   ├── go.sum
│       │   └── main.go
│       └── app3/
│           ├── Dockerfile
│           ├── Makefile
│           ├── go.mod
│           ├── go.sum
│           └── main.go
├── http-echo-service/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── deployment.yaml
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── http-event-subscriber/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── clooudevent.json
│   ├── config/
│   │   └── pubsub.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── order-cancellation/
│   ├── README.md
│   ├── demo/
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── component/
│   │   │   ├── audit-store.yaml
│   │   │   ├── email.yaml
│   │   │   ├── queue.yaml
│   │   │   └── workflow-store.yaml
│   │   ├── config/
│   │   │   └── order-cancel.json
│   │   ├── data/
│   │   │   ├── cancellation.json
│   │   │   ├── email.json
│   │   │   └── meta.json
│   │   └── deployment/
│   │       ├── auditor.yaml
│   │       ├── ingress.yaml
│   │       ├── space.yaml
│   │       ├── viewer.yaml
│   │       └── workflow.yaml
│   └── src/
│       ├── fn/
│       │   ├── .gitignore
│       │   ├── DaprAzFn.csproj
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── ReceiveEvent.cs
│       │   ├── config/
│       │   │   ├── meta.json
│       │   │   ├── pubsub.yaml
│       │   │   └── statestore.yaml
│       │   ├── host.json
│       │   └── local.settings.json
│       └── viewer/
│           ├── Dockerfile
│           ├── Makefile
│           ├── config/
│           │   └── queue.yaml
│           ├── go.mod
│           ├── go.sum
│           ├── main.go
│           └── resource/
│               ├── static/
│               │   ├── css/
│               │   │   └── app.css
│               │   └── js/
│               │       └── app.js
│               └── template/
│                   ├── footer.html
│                   ├── header.html
│                   └── index.html
├── pipeline/
│   ├── README.md
│   ├── k8s/
│   │   ├── ingress.yaml
│   │   ├── process-pubsub.yaml
│   │   ├── processor.yaml
│   │   ├── provider.yaml
│   │   ├── scorer.yaml
│   │   ├── space.yaml
│   │   ├── state.yaml
│   │   ├── tweeter-pubsub.yaml
│   │   ├── twitter.yaml
│   │   └── viewer.yaml
│   ├── sentiment-scorer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── config/
│   │   │   └── secret.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tweet-processor/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── result-pubsub.yaml
│   │   │   └── source-pubsub.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tweet-provider/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── config/
│   │   │   ├── pubsub.yaml
│   │   │   ├── secret.yaml
│   │   │   ├── state.yaml
│   │   │   └── twitter.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── tweet-viewer/
│       ├── Dockerfile
│       ├── Makefile
│       ├── config/
│       │   └── source-pubsub.yaml
│       ├── go.mod
│       ├── go.sum
│       ├── main.go
│       ├── resource/
│       │   ├── static/
│       │   │   ├── css/
│       │   │   │   └── app.css
│       │   │   └── js/
│       │   │       └── app.js
│       │   └── template/
│       │       ├── footer.html
│       │       ├── header.html
│       │       └── index.html
│       └── tweet.json
├── setup/
│   ├── Makefile
│   ├── README.md
│   ├── aks/
│   │   ├── Makefile
│   │   └── README.md
│   ├── config/
│   │   ├── actor-dashboard.json
│   │   ├── fluentd-config.yaml
│   │   ├── fluentd.yaml
│   │   ├── ingress-annotations.yaml
│   │   ├── ingress-config.yaml
│   │   ├── ingress-template.yaml
│   │   ├── namespace-template.yml
│   │   ├── sidecar-dashboard.json
│   │   ├── system-services-dashboard.json
│   │   └── zipkin.yaml
│   ├── gke/
│   │   ├── Makefile
│   │   └── README.md
│   └── kubectl-install-dapr
└── state-change-handler/
    ├── Dockerfile
    ├── Makefile
    ├── README.md
    ├── config/
    │   ├── pubsub.yaml
    │   └── statechange.yaml
    ├── go.mod
    ├── go.sum
    └── main.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# VS Code 
Debug

# Test binary, built with `go test -c`
*.test

# Output
*.out

# mac
.DS_Store

# bin 
bin

# vendored dependnacies 
vendor

# certs 
*.pem 

# secrets
secrets.json

# certs
certs
setup/certs

# other 
setup/config/ingress.yaml
setup/config/namespace.yml


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Mark Chmarny

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Dapr demos

Collection of personal [Dapr](https://dapr.io) demos.

> Note, some of these demos require latest version of Dapr, Ingress gateway, Observability components, or cluster-local Redis and Mongo services. To create Kubernetes cluster with all these components on AKS, or quickly configure an existing cluster, consider the [Dapr Cluster Setup](./setup) utility.


* Bindings
  * [Scheduling using cron](./cron-binding) - Using scheduler to execute service 
  * [Tweet stream](./pipeline/tweet-provider) - Subscribing to a Twitter even stream and publishing to a pub/sub topic
  * [State change handler](./state-change-handler) - RethinkDB state changes streamed into topic
* Eventing
  * [gRPC event subscriber](./grpc-event-subscriber) - Subscribing to topic and processing its events using gRPC service
  * [HTTP event subscriber](./http-event-subscriber) - Subscribing to topic and processing its events using HTTP service
* Services 
  * [gRPC echo service](./grpc-echo-service) - gRPC service invocation example
  * [HTTP echo service](./http-echo-service) - HTTP service invocation example
  * [Sentiment Scorer](./pipeline/sentiment-scorer) - Sentiment scoring serving backed by Azure Cognitive Service 
* Integrations
  * [Components in ACI](./dapr-api-on-aci) - Dapr components as microservices on ACI without app
  * [Component in Kubernetes](./component-api) - Dapr components as microservices on Kubernetes without app
  * [Dapr Apps in ACI](./dapr-aci) - Deploying apps with Dapr sidecar and components on ACI
  * [Dapr with APIM](./apim-gateway) - Dapr API using Azure API Management self-hosted gateway
  * [Dapr API on Ingress](./daprized-ingress) - Expose Dapr API on Kubernetes Ingress Controller using NGINX
  * [Dapr GitOps](https://github.com/mchmarny/git-ops) - GitHub Actions build pipeline for Dapr apps
* Solutions
  * [Order cancellation](./order-cancellation) - multiple Dapr service integrations with observability
  * [Pipeline](./pipeline) - Demos combining Twitter binding, Sentiment scoring, Multi Pub/Sub Processor, and WebSocket Viewer app
  * [Fan-out](./fan-out) - Single message source "broadcasted" to multiple, configurable targets (e.g. Redis PubSub, HTTP, gRPC)
  * [Hardened](./hardened) - Example of multi-microservice app with tightly controlled access to secrets, components, and full invoking service identity validation
* Templates
  * [Dapr gRPC Service](https://github.com/mchmarny/dapr-grpc-service-template) - gRPC service template
  * [Dapr HTTP Event Subscriber](https://github.com/mchmarny/dapr-http-event-subscriber-template) - Event subscriber HTTP service template
  * [Dapr gRPC Event Subscriber](https://github.com/mchmarny/dapr-grpc-event-subscriber-template) - Event subscriber gRPC service template 
  * [dapr-http-cron-handler](https://github.com/mchmarny/dapr-http-cron-handler-template) - Scheduled service development template

## Disclaimer

This is my personal project and it does not represent my employer. While I do my best to ensure that everything works, I take no responsibility for issues caused by this code.

## License

This software is released under the [MIT](./LICENSE)


================================================
FILE: apim-gateway/README.md
================================================
# Dapr & Azure API Management Integration Demo

Dapr integration with [Azure API Management](https://azure.microsoft.com/en-us/services/api-management/) (APIM) using self-hosted gateway on Kubernetes. 

![APIM Self-hosted Gateway Overview](img/overview-diagram.png)

In this demo we will walk through the configuration of API Management service and its self-hosted gateway on Kubernetes. To illustrate the Dapr integration we will also review three Dapr use-cases:

* Invocation of a specific Dapr service method
* Publishing content to a Pub/Sub topic 
* Binding invocation with request content transformation

In addition, we will overview the use of APIM tracing to debug your configuration. 

> While you can accomplish everything we show here in Azure portal, to make this demo easier to reliably reproduce, we will be using only the Azure CLI and APIs.

## Prerequisite 

* [Azure account](https://azure.microsoft.com/en-us/free/)
* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
* [Kubernetes cluster with Dapr](https://github.com/dapr/docs/blob/v0.9.0/getting-started/environment-setup.md#installing-dapr-on-a-kubernetes-cluster)
* [Helm](https://helm.sh/docs/intro/install/)

## Terminology

You will see a few different APIs being used throughout this demo. At one point we are even going to use one API to manage another (API inception?). Here is short summary to help you keep all these APIs straight. Hope it helps: 

* [Azure API](https://docs.microsoft.com/en-us/rest/api/apimanagement/) - this is the API provided by Azure to manage its service (yes, including the API Management Service)
* [API in APIM](https://docs.microsoft.com/en-us/azure/api-management/edit-api) - is the API which we will define in APIM service. Its operations will be used by the users
* [Dapr API](https://github.com/dapr/docs/tree/master/reference/api#dapr-api-reference) - are the RESTful HTTP APIs defined by Dapr which developers interact with building applications

## Setup 

To make this demo easier to reproduce, start by exporting the name for your new Azure API Management (APIM) service.

> Note, the name of your API Management service instance has to be globally unique!

```shell
export APIM_SERVICE_NAME="dapr-apim-demo"
```

In addition also export the Azure [Subscription ID](https://docs.bitnami.com/azure/faq/administration/find-subscription-id/) and [Resource Group](https://docs.bitnami.com/azure/faq/administration/find-deployment-resourcegroup-id/) where you want to create that service.

```shell
export AZ_SUBSCRIPTION_ID="your-subscription-id"
export AZ_RESOURCE_GROUP="your-resource-group"
```

## Azure API Management 

We will start by configuring the Azure API Management service.

### Service Creation

Create service instance:

> The `publisher-email` and `publisher-name` are only required to receive system notifications e-mails.

```shell
az apim create --name $APIM_SERVICE_NAME \
               --subscription $AZ_SUBSCRIPTION_ID \
               --resource-group $AZ_RESOURCE_GROUP \
               --publisher-email "you@your-domain.com" \
               --publisher-name "Your Name"
```

> Note, depending on the SKU and resource group configuration, this operation may take 15+ min. While this running, consider quick read on [API Management Concepts](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations)

### API Configuration

Each [API operation](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations) defined in APIM will map to one Dapr API. To define these mappings you will use OpenAPI format defined in [apim/api.yaml](./apim/api.yaml) file. You will need to update the OpenAPI file with the name of the APIM service created above:

```yaml
servers:
  - url: http://<YOUR-APIM-SERVICE-NAME>.azure-api.net
  - url: https://<YOUR-APIM-SERVICE-NAME>.azure-api.net
```

When finished, import that OpenAPI definition fle into APIM service instance:

```shell
az apim api import --path / \
                   --api-id dapr \
                   --subscription $AZ_SUBSCRIPTION_ID \
                   --resource-group $AZ_RESOURCE_GROUP \
                   --service-name $APIM_SERVICE_NAME \
                   --display-name "Demo Dapr Service API" \
                   --protocols http https \
                   --subscription-required true \
                   --specification-path apim/api.yaml \
                   --specification-format OpenApi
```

> Notice the `subscription-required` parameter is set to `true` which means that all invocations against the `dapr` API will need a subscription key. We cover how to obtain the subscription key later. 

### Azure API Token

Export the Azure management API token to use through this demo.

```shell
export AZ_API_TOKEN=$(az account get-access-token --resource=https://management.azure.com --query accessToken --output tsv)
```

> If you receive an error later that your token expired, just re-run this command

### Policy Management

APIM [Policies](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#--policies) are sequentially executed on each request. We will start by defining "global" policy to throttle all operation invocations on our API, then add individual policies for each operation to add specific options.

#### Global Policy

APIM policies are defined inside of inbound, outbound, and backend elements. In our case to apply policy that will rate-limit all requests on all operations (before they are forwarded to Dapr API), we will place the global policy within the `inbound` section. 

> Note, the rate limit quota we defined here is being shared across all the replicas of self-hosted gateway. In default configuration, where there are 2 replicas, this policy would actually be half of the permitted calls per minute.

```xml
<policies>
     <inbound>
          <rate-limit-by-key  
               calls="120"
               renewal-period="60"
               increment-condition="@(context.Response.StatusCode == 200)"
               counter-key="@(context.Request.IpAddress)" />
     </inbound>
     ...
</policies>
``` 

Apply that [policy](apim/policy-all.json) to all operations submit it to the Azure management API.

```shell
curl -i -X PUT \
     -d @apim/policy-all.json \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/policies/policy?api-version=2019-12-01"
```

If everything goes well, the management API will return the created policy.

#### Echo Service Policy 

The Dapr service invocation handles all the service discovery, so to invoke a specific method on any Dapr service users follow this API: 

```http
POST/GET/PUT/DELETE /v1.0/invoke/<appId>/method/<method-name>
```

To enable users to invoke the `echo` method on Dapr service with ID of `echo-service` we will create a policy that inherits the global policy (`<base />`) first, to ensure only authorize service invocation are passed to the backend Dapr API. Then to "map" the invocation we set `dapr` as the "backend-id" and define the Dapr service and method attributes to specific service ID and method name.

```xml
<policies>
     <inbound>
          <base />
          <set-backend-service 
               backend-id="dapr" 
               dapr-app-id="echo-service" 
               dapr-method="echo" />
     </inbound>
     ...
</policies>
```

To apply [this policy](apim/policy-echo.json) to the `echo` operation on our API, submit it to the Azure management API:

```shell
curl -i -X PUT \
     -d @apim/policy-echo.json \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/echo/policies/policy?api-version=2019-12-01"
```

If everything goes well, the management API will return the created policy. Additional information about Dapr Service Invocation in APIM are available [here](https://aka.ms/apim/dapr/invoke). 

Also, since the external mapping of the API user invocations to Dapr is done in APIM policy, it can be easily re-mapped to any other version as the API implementation evolves over time. 

![](img/backend-policy.png)

#### Message Topic Policy 

In addition to Dapr service invocation, APIM can also be used to publish to Dapr Pub/Sub API:

```http
POST /v1.0/publish/<pubsubname>/<topic>
```

To expose the `messages` topic configured in the `demo-events` component we will start by inheriting the global policy like before, and then set the publish policy to format the request that will be passed to the Dapr Pub/Sub API:

```xml
<policies>
     <inbound>
        <base />
        <publish-to-dapr 
               topic="@("demo-events/messages")" 
               response-variable-name="pubsub-response"
        >@(context.Request.Body.As<string>())</publish-to-dapr>
        <return-response 
               response-variable-name="pubsub-response" />
    </inbound>
     ...
</policies>
```

To apply [this policy](apim/policy-message.json) to the `message` operation on our API, submit it to the Azure management API:


```shell
curl -i -X PUT \
     -d @apim/policy-message.json \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/message/policies/policy?api-version=2019-12-01"
```

If everything goes well, the management API will return the created policy. Additional information about Dapr Pub/Sub support in APIM are available [here](https://aka.ms/apim/dapr/pubsub).

#### Save Binding Policy 

In our final case, we are going to overview exposing the Dapr binding API.

```http
POST/PUT /v1.0/bindings/<name>
```

In contrast to the previous policies, rather than just forwarding the original request content, we are going to create a brand new request based on the content of the original request and mapping it to the format expected by Dapr API. This capability comes handy when your API needs to stay the same while the backing service evolves API evolves over time. Consider the payload expected by Dapr binding API: 

```json
{
  "data": "",
  "metadata": {
    "": "",
    "": ""
  },
  "operation": ""
}
```

The policy will first define a `key` variable that will be generated using system guid. Once defined, that variable can be used later on in the policy. To accommodate the binding format expected by Dapr, the policy will then set `operation` attribute in APIM `invoke-dapr-binding` policy, and set `metadata` items to:

* `source` which will be a static value indicating the record came from `APIM`
* `client-ip` which will be set to the client request IP
* `key` which will be set to the value of the variable defined above

Finally, for `data`, we simply use the original content of the client request.

```xml
<policies>
    <inbound>
        <base />
        <set-variable name="key" 
                      value="@{ return Guid.NewGuid().ToString(); }" />
        <invoke-dapr-binding 
                      name="demo-binding" 
                      operation="create" 
                      response-variable-name="binding-response">
            <metadata>
                <item key="source">APIM</item>
                <item key="client-ip">@( context.Request.IpAddress )</item>
                <item key="key">@( (string)context.Variables["key"] )</item>
            </metadata>
            <data>@( context.Request.Body.As<string>() )</data>
        </invoke-dapr-binding>
        <return-response response-variable-name="binding-response" />
    </inbound>
     ...
</policies>
```

To apply [this policy](apim/policy-save.json) to the `save` operation on our API, submit it to the Azure management API:

```shell
curl -i -X PUT \
     -d @apim/policy-save.json \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/save/policies/policy?api-version=2019-12-01"
```

> Note, the support in APIM for bindings is still rolling out across Azure regions. You can safely skip this section and just demo service invocation and topic publishing if you receive an error that `invoke-dapr-binding` is not recognize.

If everything goes well, the management API will return the created policy. Additional information about Dapr Binding support in APIM are available [here](https://aka.ms/apim/dapr/bind). 
 
### Gateway Configuration

To create a self-hosted gateway which will be then deployed to the Kubernetes cluster, first, we need to create the `demo-apim-gateway` object in APIM:

```shell
curl -i -X PUT -d '{"properties": {"description": "Dapr Gateway","locationData": {"name": "Virtual"}}}' \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway?api-version=2019-12-01"
```

And then map that gateway to the previously created API:

```shell
curl -i -X PUT -d '{ "properties": { "provisioningState": "created" } }' \
     -H "Content-Type: application/json" \
     -H "If-Match: *" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/apis/dapr?api-version=2019-12-01"
```

If everything goes well, the API returns JSON of the created objects.

## Kubernetes 

Switching now to the Kubernetes cluster...

### Dependencies 

To showcase the ability to expose Dapr pub/sub and binding APIs in APIM, we are going to need [Dapr components](https://github.com/dapr/docs/tree/master/concepts#components) configured on the cluster. 

> Note, while Dapr supports some 75+ different components, to keep things simple in this demo we will use Redis as both pub/sub and binding backing service

Start with adding the Redis repo to your Helm charts:

```shell
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
```

And install Redis and wait for the deployment to complete:

> Note, for simplicity, we are deploying everything into the `default` namespace.

```shell
helm install redis bitnami/redis  
kubectl rollout status statefulset.apps/redis-master
kubectl rollout status statefulset.apps/redis-slave
```

### Dapr Components 

Dapr's modular design means that we can easily extend its functionality using [components](https://github.com/dapr/docs/tree/master/concepts#components). The specific implementation for these components which can be any number of the readily available Dapr building blocks is done in configuration. That means that it's also easy to swap or reconfigure them at runtime without the need to modify your code. 

![](img/dapr-building-blocks.png)

To create the binding component to point to the above created Redis cluster the configuration looks like this:

```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: demo-events
spec:
  type: pubsub.redis
  metadata:
  - name: redisHost
    value: redis-master.default.svc.cluster.local:6379
  - name: redisPassword
    secretKeyRef:
      name: redis
      key: redis-password
  - name: allowedTopics
    value: "messages"
```

Notice we are using the secret created by Redis for password so that our configuration doesn't include any secure information. We also specify that only the `messages` topic should be supported in this case. 

To apply these component configurations run: 

```shell
kubectl apply -f k8s/pubsub.yaml
kubectl apply -f k8s/binding.yaml
```

> Note, if you updated components after deploying the gateway you will need to restart the deployments.

```shell
kubectl rollout restart deployment/event-subscriber
kubectl rollout status deployment/event-subscriber
kubectl rollout restart deployment/demo-apim-gateway
kubectl rollout status deployment/demo-apim-gateway
```

To check if the components were registered correctly in Dapr, inspect the `daprd` logs in `demo-apim-gateway` pod for `demo-events` and `demo-binding`:

```shell
kubectl logs -l app=demo-apim-gateway -c daprd --tail=200
```

### Dapr Services 

To deploy your application as a Dapr service all you need to do is augment your Kubernetes deployment template with few Dapr annotations.

```yaml
annotations:
     dapr.io/enabled: "true"
     dapr.io/app-id: "event-subscriber"
     dapr.io/app-port: "8080"
```

> To learn more about Kubernetes sidecar configuration see [Dapr docs](https://github.com/dapr/docs/blob/master/concepts/configuration/README.md#kubernetes-sidecar-configuration).

For this demo we will use a pre-build Docker images of two applications: [gRPC Echo Service](https://github.com/mchmarny/dapr-demos/tree/master/grpc-echo-service) and [HTTP Event Subscriber Service](https://github.com/mchmarny/dapr-demos/tree/master/http-event-subscriber). The Kubernetes deployment files for both of these are located here:

* [k8s/echo-service.yaml](k8s/echo-service.yaml)
* [k8s/event-subscriber.yaml](k8s/event-subscriber.yaml)

Deploy both of these and check that it is ready:

```shell
kubectl apply -f k8s/echo-service.yaml
kubectl apply -f k8s/event-subscriber.yaml
kubectl get pods -l demo=dapr-apim -w
```

> Service is ready when its status is `Running` and the ready column is `2/2` (Dapr and our echo service containers both started)

```shell
NAME                                READY   STATUS    RESTARTS   AGE
echo-service-668986b998-v2ssp       2/2     Running   0          10m
event-subscriber-7d68b67d9d-5v7bf   2/2     Running   0          10m
```

To make sure that the event subscriber connects to the Redis service you can query the service logs

```shell
kubectl logs -l app=event-subscriber -c daprd | grep demo-events
```

You should see entries containing: 

```shell
app responded with subscriptions [{demo-events messages /messages map[]}]
app is subscribed to the following topics: [messages] through pubsub=demo-events
subscribing to topic=messages on pubsub=demo-events
```

### Self-hosted APIM Gateway 

To connect the self-hosted gateway to APIM service, we will need to create a Kubernetes secret with the APIM gateway key. Start by getting the key which your gateway will use to connect to from APIM:

> Note, the maximum validity for access tokens is 30 days. Update the below `expiry` parameter to be withing 30 days from today

```shell
curl -i -X POST -d '{ "keyType": "primary", "expiry": "2020-10-10T00:00:01Z" }' \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/generateToken?api-version=2019-12-01"
```

Copy the content of `value` from the response and create a secret:

```shell
kubectl create secret generic demo-apim-gateway-token --type Opaque --from-literal value="GatewayKey paste-the-key-here"
```

> Make sure the secret includes the `GatewayKey` and a space ` ` as well as the value of your token (e.g. `GatewayKey a1b2c3...`)

Now, create a config map containing the APIM service endpoint that will be used to configure your self-hosted gateway:

```shell
kubectl create configmap demo-apim-gateway-env --from-literal \
     "config.service.endpoint=https://${APIM_SERVICE_NAME}.management.azure-api.net/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}?api-version=2019-12-01"
```

And finally, deploy the gateway and check that it's ready:

```shell
kubectl apply -f k8s/gateway.yaml
kubectl get pods -l app=demo-apim-gateway
```

> Note, the self-hosted gateway is deployed with 2 replicas to ensure availability during upgrades. 

Make sure both instances have status `Running` and container is ready `2/2` (gateway container + Dapr side-car).

```shell
NAME                                 READY   STATUS    RESTARTS   AGE
demo-apim-gateway-6dfb968f5c-cb4t7   2/2     Running   0          26s
demo-apim-gateway-6dfb968f5c-gxrrq   2/2     Running   0          26s
```

To check on the gateway logs:

```shell
kubectl logs -l app=demo-apim-gateway -c demo-apim-gateway
```

## Usage (API Test)

With APIM configured and self-hosted gateway deployed we are ready to test. Start by capturing the cluster load balancer ingress IP:

```shell
export GATEWAY_IP=$(kubectl get svc demo-apim-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
```

### API Subscription Key 

All of the APIs we defined in this demo are protected with subscription key. To invoke them, we will first need a subscription key: 

```shell
curl -i -H POST -d '{}' -H "Authorization: Bearer ${AZ_API_TOKEN}" \
     "https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/subscriptions/master/listSecrets?api-version=2019-12-01"
```

The response will include both the primary and secondary keys. Copy one of them and export so we can use it for the rest of the demo:

```shell
export AZ_API_SUB_KEY="your-api-subscription-key"
```

### Service Invocation 

To invoke the backing gRPC service over Dapr API exposed by APIM run:

```shell
curl -i -X POST -d '{ "message": "hello" }' \
     -H "Content-Type: application/json" \
     -H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
     -H "Ocp-Apim-Trace: true" \
     "http://${GATEWAY_IP}/echo"
```

If everything is configured correctly, you should see the response from your backing Dapr service: 

```json 
{ "message": "hello" }
```

In addition, you can also check the `echo-service` logs:

```shell
kubectl logs -l app=echo-service -c service
```

### Message Publishing 

To post a message to the Dapr Pub/Sub API exposed on APIM run:

```shell
curl -i -X POST \
     -d '{ "content": "hello" }' \
     -H "Content-Type: application/json" \
     -H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
     -H "Ocp-Apim-Trace: true" \
     "http://${GATEWAY_IP}/message"
```

If everything is configured correctly, you will see `200` status code in the header, indicating the message was successfully delivered to the Dapr API.

You can also check the `event-subscriber` logs:

```shell
kubectl logs -l app=event-subscriber -c service
```

There should be an entry similar to this: 

```shell
event - PubsubName:demo-events, Topic:messages, ID:24f0e6f0-ab29-4cd6-8617-6c6c36ac1171, Data: map[message:hello]
```

### Binding Invocation

To save a record into database using the Dapr binding API exposed by APIM run:

```shell
curl -i -X POST \
     -d '{"city":"PDX","time":"1600171062","metric":"aqi","value": 457}' \
     -H "Content-Type: application/json" \
     -H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
     -H "Ocp-Apim-Trace: true" \
     "http://${GATEWAY_IP}/save"
```

If everything is configured correctly, you will see `200` status code in the header indicating the binding was successfully triggered on the Dapr API and our record successfully saved into the DB. 

### Debugging 

Notice in each one of our API invocations we have been including the `Ocp-Apim-Trace: true` header parameter. APIM provides an ability to trace requests across the policy execution chain which is helps in debugging your policy. The response of each one fo the above invocation includes the `Ocp-Apim-Trace-Location` header parameter. Just paste the value of that parameter into your browser to see the full trace stack in JSON. The trace can get pretty long so here are few Dapr-specific snippets: 


```json 
...
{
    "source": "request-forwarder",
    "timestamp": "2020-09-11T11:15:52.9405903Z",
    "elapsed": "00:00:00.1382166",
    "data": {
        "message": "Request is being forwarded to the backend service. Timeout set to 300 seconds",
        "request": {
            "method": "POST",
            "url": "http://localhost:3500/v1.0/publish/demo-events/messages"
        }
    }
},
{
    "source": "publish-to-dapr",
    "timestamp": "2020-09-11T11:15:53.1899121Z",
    "elapsed": "00:00:00.3875400",
    "data": {
        "response": {
            "status": {
                "code": 200,
                "reason": "OK"
            },
            "headers": [
                {
                    "name": "Server",
                    "value": "fasthttp"
                },
                {
                    "name": "Date",
                    "value": "Fri, 11 Sep 2020 11:15:52 GMT"
                },
                {
                    "name": "Content-Length",
                    "value": "0"
                },
                {
                    "name": "Traceparent",
                    "value": "00-5b1f0bdfc2191742a4635a906359a7aa-196f5df2e977b00a-01"
                }
            ]
        }
    }
}
...
```

## Summary 

This demo illustrated how to setup the APIM service and deploy the self-hosted gateway into your cluster. Using this gateway you can mange access to any number of Dapr services hosted on Kubernetes. You can find out more about all the features of APIM (e.g. Discovery, Caching, Logging etc.) [here](https://azure.microsoft.com/en-us/services/api-management/).

## Cleanup 

```shell
kubectl delete -f k8s/gateway.yaml
kubectl delete secret demo-apim-gateway-token
kubectl delete configmap demo-apim-gateway-env

kubectl delete -f k8s/echo-service.yaml
kubectl delete -f k8s/event-subscriber.yaml

kubectl delete -f k8s/pubsub.yaml
kubectl delete -f k8s/binding.yaml

az apim delete --name $APIM_SERVICE_NAME --no-wait --yes
```



================================================
FILE: apim-gateway/apim/api.yaml
================================================
openapi: 3.0.1
info:
  title: dapr
  version: '1.0'
servers:
  - url: http://dapr-apim-demo.azure-api.net
  - url: https://dapr-apim-demo.azure-api.net
paths:
  /echo:
    post:
      summary: Echo Service
      description: Invoke service using Dapr API
      operationId: echo
      requestBody:
        content:
          application/json:
            example:
              message: hello
      responses:
        '200':
          description: ''
  /message:
    post:
      summary: Message Topic
      description: Post to topic using Dapr API
      operationId: message
      requestBody:
        content:
          application/json:
            example:
              content: hello
      responses:
        '200':
          description: ''
  /save:
    post:
      summary: DB Binding
      description: DB binding using Dapr API
      operationId: save
      requestBody:
        content:
          application/json:
            example:
              city: PDX,
              time: 1600171062
              metric: aqi
              value: 457
      responses:
        '200':
          description: ''

================================================
FILE: apim-gateway/apim/policy-all.json
================================================
{
    "properties": {
      "format": "xml",
      "value": "<policies><inbound><rate-limit-by-key calls=\"120\" renewal-period=\"60\" increment-condition=\"@(context.Response.StatusCode == 200)\" counter-key=\"@(context.Request.IpAddress)\" /></inbound><backend><forward-request /></backend><outbound /><on-error /></policies>"
    }
}

================================================
FILE: apim-gateway/apim/policy-echo.json
================================================
{
    "properties": {
      "format": "xml",
      "value": "<policies><inbound><base /><set-backend-service backend-id=\"dapr\" dapr-app-id=\"echo-service\" dapr-method=\"echo\" /></inbound><backend><base /></backend><outbound></outbound><on-error><base /></on-error></policies>"
    }
}

================================================
FILE: apim-gateway/apim/policy-message.json
================================================
{
    "properties": {
      "format": "xml",
      "value": "<policies><inbound><base /><publish-to-dapr topic=\"@(&quot;demo-events/messages&quot;)\" response-variable-name=\"pubsub-response\">@( context.Request.Body.As&lt;string&gt;() )</publish-to-dapr><return-response response-variable-name=\"pubsub-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
    }
}

================================================
FILE: apim-gateway/apim/policy-save.json
================================================
{
    "properties": {
      "format": "xml",
      "value": "<policies><inbound><base /><set-variable name=\"key\" value=\"@{ return Guid.NewGuid().ToString(); }\" /><invoke-dapr-binding name=\"demo-binding\" operation=\"create\" response-variable-name=\"binding-response\"><metadata><item key=\"source\">APIM</item><item key=\"client-ip\">@( context.Request.IpAddress )</item><item key=\"key\">@( (string)context.Variables[\"key\"] )</item></metadata><data>@( context.Request.Body.As&lt;string&gt;() )</data></invoke-dapr-binding><return-response response-variable-name=\"binding-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
    }
}

================================================
FILE: apim-gateway/k8s/binding.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: demo-binding
spec:
  type: bindings.redis
  metadata:
  - name: redisHost
    value: redis-master.default.svc.cluster.local:6379
  - name: redisPassword
    secretKeyRef:
      name: redis
      key: redis-password

================================================
FILE: apim-gateway/k8s/echo-service.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-service
  labels:
    app: echo-service
    demo: dapr-apim
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo-service
  template:
    metadata:
      labels:
        app: echo-service
        demo: dapr-apim
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "echo-service"
        dapr.io/app-protocol: "grpc"
        dapr.io/app-port: "60002"
        dapr.io/config: "tracing"
        dapr.io/log-as-json: "true"
        dapr.io/log-level: "debug"
    spec:
      containers:
      - name: service
        image: mchmarny/grpc-echo-service:v0.11.1
        imagePullPolicy: Always
        ports:
        - containerPort: 60002
        env:
        - name: ADDRESS
          value: ":60002"

================================================
FILE: apim-gateway/k8s/event-subscriber.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
  name: event-subscriber
  labels:
    app: event-subscriber
    demo: dapr-apim
spec:
  selector:
    matchLabels:
      app: event-subscriber
  template:
    metadata:
      labels:
        app: event-subscriber
        demo: dapr-apim
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "event-subscriber"
        dapr.io/app-port: "8080"
        dapr.io/config: "tracing"
        dapr.io/log-as-json: "true"
        dapr.io/log-level: "debug"
    spec:
      containers:
      - name: service
        image: mchmarny/http-event-subscriber:v0.11.1
        ports:
        - containerPort: 8080
        env:
        - name: PORT
          value: "8080"
        - name: PUBSUB_NAME
          value: "demo-events"
        - name: TOPIC_NAME
          value: "messages"

================================================
FILE: apim-gateway/k8s/gateway.yaml
================================================
# NOTE: Before deploying to a production environment, please review the documentation -> https://aka.ms/self-hosted-gateway-production
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-apim-gateway
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-apim-gateway
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 25%
  template:
    metadata:
      labels:
        app: demo-apim-gateway
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "demo-apim-gateway"
        dapr.io/config: "tracing"
        dapr.io/log-as-json: "true"
        dapr.io/log-level: "debug"
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: demo-apim-gateway
        image: mcr.microsoft.com/azure-api-management/gateway:beta
        ports:
        - name: http
          containerPort: 8080
        - name: https
          containerPort: 8081
        readinessProbe:
          httpGet:
            path: /internal-status-0123456789abcdef
            port: http
            scheme: HTTP
          initialDelaySeconds: 0
          periodSeconds: 5
          failureThreshold: 3
          successThreshold: 1
        env:
        - name: config.service.auth
          valueFrom:
            secretKeyRef:
              name: demo-apim-gateway-token
              key: value
        envFrom:
        - configMapRef:
            name: demo-apim-gateway-env
---
apiVersion: v1
kind: Service
metadata:
  name: demo-apim-gateway
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: https
    port: 443
    targetPort: 8081
  selector:
    app: demo-apim-gateway

================================================
FILE: apim-gateway/k8s/pubsub.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: demo-events
spec:
  type: pubsub.redis
  metadata:
  - name: redisHost
    value: redis-master.default.svc.cluster.local:6379
  - name: redisPassword
    secretKeyRef:
      name: redis
      key: redis-password
  - name: allowedTopics
    value: "messages"

================================================
FILE: autoscaling-on-queue/README.md
================================================
# Autoscaling Dapr service based on queue depth 

Dapr, with its modular building-block approach, along with the 10+ different Pub/Sub components, makes it easy to write message processing microservices. Since Dapr runs in VM, on bare-metal, in the Cloud, or even on the Edge... the autoscaling Dapr services is left to the hosting later. 

In case of Kubernetes, Dapr integrates with [Keda](https://github.com/kedacore/keda), an event driven autoscaler for Kubernetes. In this demo I'll walk through the configuration of Dapr microservice to scale along with the back pressure on [Kafka](https://kafka.apache.org) queue that service processes. 

![](image/diagram.png)

## Setup 

The autoscaling demo requires [Dapr](https://dapr.io). If you don't already have a Kubernetes cluster with Dapr installed you can use the included [setup](../setup) to configure all the dependencies. 

### Keda 

Start by install [Keda](https://github.com/kedacore/keda) into the cluster and wait for it become ready:

```shell
kubectl apply -f deployment/keda-2.0.0-beta.yaml
kubectl rollout status deployment.apps/keda-operator -n keda
```

### Kafka (optional)

Next, if you don't have access to Kafka you can use these instructions to install Kafka into the cluster:

```shell
helm repo add confluentinc https://confluentinc.github.io/cp-helm-charts/
helm repo update
kubectl create ns kafka
helm install kafka confluentinc/cp-helm-charts -n kafka \
		--set cp-schema-registry.enabled=false \
		--set cp-kafka-rest.enabled=false \
		--set cp-kafka-connect.enabled=false \
		--set dataLogDirStorageClass=default \
		--set dataDirStorageClass=default \
		--set storageClass=default
kubectl rollout status deployment.apps/kafka-cp-control-center -n kafka
kubectl rollout status deployment.apps/kafka-cp-ksql-server -n kafka
kubectl rollout status statefulset.apps/kafka-cp-kafka -n kafka
kubectl rollout status statefulset.apps/kafka-cp-zookeeper -n kafka
```

When done, also deploy Kafka client and wait until it's ready:

```shell
kubectl apply -n kafka -f deployment/kafka-client.yaml
kubectl wait -n kafka --for=condition=ready pod kafka-client --timeout=120s
```

Next, create the `metric` topic which we will use in this demo:

> The number of `partitions` is connected to the maximum number of replicas Keda will create. 

```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
		--zookeeper kafka-cp-zookeeper-headless:2181 \
		--topic metric \
		--create \
		--partitions 10 \
		--replication-factor 3 \
		--if-not-exists
```

## Deployment

To configure the autoscaling demo we will deploy two deployments: `subscriber` which will be used to process messages of the `metric` queue in Kafka, and the `producer`, which will be publishing messages. To make the `producer` compatible with any one of the Pub/Sub components supported by Dapr we will publish the events onto the Kafka queue using Dapr APIs. 

### Subscriber

The `subscriber` service doesn't really do anything with the messages. To resemble real-life processing which may take some time to process messages, the `subscriber` allows for explicit processing time setting. The default value is `300ms`. We will go over how to modify that later. 

To deploy the `subscriber` service, apply the [Kafka Dapr component](deployment/kafka-pubsub.yaml), the [message subscriber service](deployment/subscriber.yaml), and the [subscriber service Keda scaler](subscriber-scaler.yaml):

```shell
kubectl apply -f deployment/kafka-pubsub.yaml
kubectl apply -f deployment/subscriber.yaml
kubectl apply -f deployment/subscriber-scaler.yaml
```

When done, start watching for the number of replicas of the deployed `subscriber` service: 

```shell
watch kubectl get pods -l app=autoscaling-subscriber
```

> Note, by default the subscriber service Keda scaler is set to scale to 0, so you will not see any pods yet. We will publish data on the `metric` topic with the `producer`.

### Producer

In a second terminal session, deploy the [producer service](deployment/producer.yaml) and wait for it to be ready:

```shell
kubectl apply -f deployment/producer.yaml
kubectl rollout status deployment/autoscaling-producer
```

## Demo 

Back in the initial terminal now, some 20-30 seconds after the `producer` starts, you should see the number of `subscriber` pods being adjusted by Keda based on the number of the `metric` topic:

```shell
NAME                                      READY   STATUS    RESTARTS   AGE
autoscaling-subscriber-696ffb5c7b-64zqq   2/2     Running   0          31s
autoscaling-subscriber-696ffb5c7b-67f74   2/2     Running   0          15s
autoscaling-subscriber-696ffb5c7b-gpc2d   2/2     Running   0          7m42s
```

By default the `subscriber-scaler` is set to scale-to-zero and has the polling frequency of `15s`. You can adjust these values in [deployment/subscriber-scaler.yaml](deployment/subscriber-scaler.yaml):

```yaml
pollingInterval: 15
minReplicaCount: 0
maxReplicaCount: 10
cooldownPeriod: 30
```

To modify how long should the `subscriber` take to process each message adjust `PROCESS_DURATION` in [deployment/subscriber.yaml](deployment/subscriber.yaml) and re-apply it to the cluster:

```yaml
- name: PROCESS_DURATION
  value: "300ms"
```

Finally, to adjust the number of messages published by the producer change the `producer` in [deployment/producer.yaml](./deployment/producer.yaml) and re-apply it to the cluster:


```yaml
- name: NUMBER_OF_PUBLISHERS
  value: "1"
- name: PUBLISHERS_FREQ
  value: "100ms"
```

The `NUMBER_OF_PUBLISHERS` setting is number of channels that are used to publish events (default: 1). And the `PUBLISHERS_FREQ` is the frequency with which each channel publishes events (default: 1s). 

> There is a limit to the amount of messages a single container can produce. If you need to scale beyond that number, increase the number of `autoscaling-producer` replicas

```shell
kubectl scale -n kafka deployment/autoscaling-producer --replicas=10 
```

### Updating Components 

If you have changed already deployed Dapr component, make sure to reload the `subscriber` and `producer` deployments:

```shell
kubectl rollout restart deployment/autoscaling-subscriber
kubectl rollout status deployment/autoscaling-subscriber
kubectl rollout restart deployment/autoscaling-producer
kubectl rollout status deployment/autoscaling-producer
```

### Kafka Helpers 

Get `metric` topic offsets for `autoscaling-subscriber` consumer group:

```shell
kubectl -n kafka exec -it kafka-client -- kafka-consumer-groups \
	--bootstrap-server kafka-cp-kafka:9092 \
	--describe \
	--group autoscaling-subscriber
```

Purge the `metric` topic:

```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
	--zookeeper kafka-cp-zookeeper:2181 \
	--alter \
	--topic metric \
	--config retention.ms=1000
sleep 15
kubectl -n kafka exec -it kafka-client -- kafka-topics \
	--zookeeper kafka-cp-zookeeper:2181 \
	--alter \
	--topic metric \
	--delete-config retention.ms
```

Delete `metric` topic

```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
	--zookeeper kafka-cp-zookeeper:2181 \
	--delete \
	--topic metric
```

## Cleanup 

```shell
kubectl delete -f deployment/producer.yaml
kubectl delete -f deployment/kafka-pubsub.yaml
kubectl delete -f deployment/subscriber.yaml
kubectl delete -f deployment/subscriber-scaler.yaml
kubectl delete -f deployment/keda-2.0.0-beta.yaml
```

## Disclaimer

This is my personal project and it does not represent my employer. While I do my best to ensure that everything works, I take no responsibility for issues caused by this code.

## License

This software is released under the [MIT](../LICENSE)


================================================
FILE: autoscaling-on-queue/deployment/kafka-client.yaml
================================================
apiVersion: v1
kind: Pod
metadata:
 name: kafka-client
spec:
 containers:
  - name: kafka-client
    image: confluentinc/cp-enterprise-kafka:5.5.0
    command:
     - sh
     - -c
     - "exec tail -f /dev/null"

================================================
FILE: autoscaling-on-queue/deployment/kafka-pubsub.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: autoscaling-pubsub
spec:
  type: pubsub.kafka
  metadata:
    - name: brokers
      value: kafka-cp-kafka.kafka.svc.cluster.local:9092
    - name: authRequired
      value: "false"
    - name: allowedTopics
      value: metric
    - name: consumerID
      value: autoscaling-subscriber

================================================
FILE: autoscaling-on-queue/deployment/keda-2.0.0-beta.yaml
================================================
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app.kubernetes.io/name: keda
    app.kubernetes.io/part-of: keda-operator
    app.kubernetes.io/version: 2.0.0-beta
  name: keda
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.3.0
  creationTimestamp: null
  labels:
    app.kubernetes.io/part-of: keda-operator
    app.kubernetes.io/version: 2.0.0-beta
  name: scaledjobs.keda.sh
spec:
  additionalPrinterColumns:
  - JSONPath: .spec.triggers[*].type
    name: Triggers
    type: string
  - JSONPath: .spec.triggers[*].authenticationRef.name
    name: Authentication
    type: string
  - JSONPath: .status.conditions[?(@.type=="Ready")].status
    name: Ready
    type: string
  - JSONPath: .status.conditions[?(@.type=="Active")].status
    name: Active
    type: string
  - JSONPath: .metadata.creationTimestamp
    name: Age
    type: date
  group: keda.sh
  names:
    kind: ScaledJob
    listKind: ScaledJobList
    plural: scaledjobs
    shortNames:
    - sj
    singular: scaledjob
  scope: Namespaced
  subresources:
    status: {}
  validation:
    openAPIV3Schema:
      description: ScaledJob is the Schema for the scaledjobs API
      properties:
        apiVersion:
          description: 'APIVersion defines the versioned schema of this representation
            of an object. Servers should convert recognized schemas to the latest
            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
          type: string
        kind:
          description: 'Kind is a string value representing the REST resource this
            object represents. Servers may infer this from the endpoint the client
            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
          type: string
        metadata:
          type: object
        spec:
          description: ScaledJobSpec defines the desired state of ScaledJob
          properties:
            envSourceContainerName:
              type: string
            failedJobsHistoryLimit:
              format: int32
              type: integer
            jobTargetRef:
              description: JobSpec describes how the job execution will look like.
              properties:
                activeDeadlineSeconds:
                  description: Specifies the duration in seconds relative to the startTime
                    that the job may be active before the system tries to terminate
                    it; value must be positive integer
                  format: int64
                  type: integer
                backoffLimit:
                  description: Specifies the number of retries before marking this
                    job failed. Defaults to 6
                  format: int32
                  type: integer
                completions:
                  description: 'Specifies the desired number of successfully finished
                    pods the job should be run with.  Setting to nil means that the
                    success of any pod signals the success of all pods, and allows
                    parallelism to have any positive value.  Setting to 1 means that
                    parallelism is limited to 1 and the success of that pod signals
                    the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
                  format: int32
                  type: integer
                manualSelector:
                  description: 'manualSelector controls generation of pod labels and
                    pod selectors. Leave `manualSelector` unset unless you are certain
                    what you are doing. When false or unset, the system pick labels
                    unique to this job and appends those labels to the pod template.  When
                    true, the user is responsible for picking unique labels and specifying
                    the selector.  Failure to pick a unique label may cause this and
                    other jobs to not function correctly.  However, You may see `manualSelector=true`
                    in jobs that were created with the old `extensions/v1beta1` API.
                    More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector'
                  type: boolean
                parallelism:
                  description: 'Specifies the maximum desired number of pods the job
                    should run at any given time. The actual number of pods running
                    in steady state will be less than this number when ((.spec.completions
                    - .status.successful) < .spec.parallelism), i.e. when the work
                    left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
                  format: int32
                  type: integer
                selector:
                  description: 'A label query over pods that should match the pod
                    count. Normally, the system sets this field for you. More info:
                    https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors'
                  properties:
                    matchExpressions:
                      description: matchExpressions is a list of label selector requirements.
                        The requirements are ANDed.
                      items:
                        description: A label selector requirement is a selector that
                          contains values, a key, and an operator that relates the
                          key and values.
                        properties:
                          key:
                            description: key is the label key that the selector applies
                              to.
                            type: string
                          operator:
                            description: operator represents a key's relationship
                              to a set of values. Valid operators are In, NotIn, Exists
                              and DoesNotExist.
                            type: string
                          values:
                            description: values is an array of string values. If the
                              operator is In or NotIn, the values array must be non-empty.
                              If the operator is Exists or DoesNotExist, the values
                              array must be empty. This array is replaced during a
                              strategic merge patch.
                            items:
                              type: string
                            type: array
                        required:
                        - key
                        - operator
                        type: object
                      type: array
                    matchLabels:
                      additionalProperties:
                        type: string
                      description: matchLabels is a map of {key,value} pairs. A single
                        {key,value} in the matchLabels map is equivalent to an element
                        of matchExpressions, whose key field is "key", the operator
                        is "In", and the values array contains only "value". The requirements
                        are ANDed.
                      type: object
                  type: object
                template:
                  description: 'Describes the pod that will be created when executing
                    a job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
                  properties:
                    metadata:
                      description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata'
                      type: object
                    spec:
                      description: 'Specification of the desired behavior of the pod.
                        More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
                      properties:
                        activeDeadlineSeconds:
                          description: Optional duration in seconds the pod may be
                            active on the node relative to StartTime before the system
                            will actively try to mark it failed and kill associated
                            containers. Value must be a positive integer.
                          format: int64
                          type: integer
                        affinity:
                          description: If specified, the pod's scheduling constraints
                          properties:
                            nodeAffinity:
                              description: Describes node affinity scheduling rules
                                for the pod.
                              properties:
                                preferredDuringSchedulingIgnoredDuringExecution:
                                  description: The scheduler will prefer to schedule
                                    pods to nodes that satisfy the affinity expressions
                                    specified by this field, but it may choose a node
                                    that violates one or more of the expressions.
                                    The node that is most preferred is the one with
                                    the greatest sum of weights, i.e. for each node
                                    that meets all of the scheduling requirements
                                    (resource request, requiredDuringScheduling affinity
                                    expressions, etc.), compute a sum by iterating
                                    through the elements of this field and adding
                                    "weight" to the sum if the node matches the corresponding
                                    matchExpressions; the node(s) with the highest
                                    sum are the most preferred.
                                  items:
                                    description: An empty preferred scheduling term
                                      matches all objects with implicit weight 0 (i.e.
                                      it's a no-op). A null preferred scheduling term
                                      matches no objects (i.e. is also a no-op).
                                    properties:
                                      preference:
                                        description: A node selector term, associated
                                          with the corresponding weight.
                                        properties:
                                          matchExpressions:
                                            description: A list of node selector requirements
                                              by node's labels.
                                            items:
                                              description: A node selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: The label key that
                                                    the selector applies to.
                                                  type: string
                                                operator:
                                                  description: Represents a key's
                                                    relationship to a set of values.
                                                    Valid operators are In, NotIn,
                                                    Exists, DoesNotExist. Gt, and
                                                    Lt.
                                                  type: string
                                                values:
                                                  description: An array of string
                                                    values. If the operator is In
                                                    or NotIn, the values array must
                                                    be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. If
                                                    the operator is Gt or Lt, the
                                                    values array must have a single
                                                    element, which will be interpreted
                                                    as an integer. This array is replaced
                                                    during a strategic merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                          matchFields:
                                            description: A list of node selector requirements
                                              by node's fields.
                                            items:
                                              description: A node selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: The label key that
                                                    the selector applies to.
                                                  type: string
                                                operator:
                                                  description: Represents a key's
                                                    relationship to a set of values.
                                                    Valid operators are In, NotIn,
                                                    Exists, DoesNotExist. Gt, and
                                                    Lt.
                                                  type: string
                                                values:
                                                  description: An array of string
                                                    values. If the operator is In
                                                    or NotIn, the values array must
                                                    be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. If
                                                    the operator is Gt or Lt, the
                                                    values array must have a single
                                                    element, which will be interpreted
                                                    as an integer. This array is replaced
                                                    during a strategic merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                        type: object
                                      weight:
                                        description: Weight associated with matching
                                          the corresponding nodeSelectorTerm, in the
                                          range 1-100.
                                        format: int32
                                        type: integer
                                    required:
                                    - preference
                                    - weight
                                    type: object
                                  type: array
                                requiredDuringSchedulingIgnoredDuringExecution:
                                  description: If the affinity requirements specified
                                    by this field are not met at scheduling time,
                                    the pod will not be scheduled onto the node. If
                                    the affinity requirements specified by this field
                                    cease to be met at some point during pod execution
                                    (e.g. due to an update), the system may or may
                                    not try to eventually evict the pod from its node.
                                  properties:
                                    nodeSelectorTerms:
                                      description: Required. A list of node selector
                                        terms. The terms are ORed.
                                      items:
                                        description: A null or empty node selector
                                          term matches no objects. The requirements
                                          of them are ANDed. The TopologySelectorTerm
                                          type implements a subset of the NodeSelectorTerm.
                                        properties:
                                          matchExpressions:
                                            description: A list of node selector requirements
                                              by node's labels.
                                            items:
                                              description: A node selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: The label key that
                                                    the selector applies to.
                                                  type: string
                                                operator:
                                                  description: Represents a key's
                                                    relationship to a set of values.
                                                    Valid operators are In, NotIn,
                                                    Exists, DoesNotExist. Gt, and
                                                    Lt.
                                                  type: string
                                                values:
                                                  description: An array of string
                                                    values. If the operator is In
                                                    or NotIn, the values array must
                                                    be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. If
                                                    the operator is Gt or Lt, the
                                                    values array must have a single
                                                    element, which will be interpreted
                                                    as an integer. This array is replaced
                                                    during a strategic merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                          matchFields:
                                            description: A list of node selector requirements
                                              by node's fields.
                                            items:
                                              description: A node selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: The label key that
                                                    the selector applies to.
                                                  type: string
                                                operator:
                                                  description: Represents a key's
                                                    relationship to a set of values.
                                                    Valid operators are In, NotIn,
                                                    Exists, DoesNotExist. Gt, and
                                                    Lt.
                                                  type: string
                                                values:
                                                  description: An array of string
                                                    values. If the operator is In
                                                    or NotIn, the values array must
                                                    be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. If
                                                    the operator is Gt or Lt, the
                                                    values array must have a single
                                                    element, which will be interpreted
                                                    as an integer. This array is replaced
                                                    during a strategic merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                        type: object
                                      type: array
                                  required:
                                  - nodeSelectorTerms
                                  type: object
                              type: object
                            podAffinity:
                              description: Describes pod affinity scheduling rules
                                (e.g. co-locate this pod in the same node, zone, etc.
                                as some other pod(s)).
                              properties:
                                preferredDuringSchedulingIgnoredDuringExecution:
                                  description: The scheduler will prefer to schedule
                                    pods to nodes that satisfy the affinity expressions
                                    specified by this field, but it may choose a node
                                    that violates one or more of the expressions.
                                    The node that is most preferred is the one with
                                    the greatest sum of weights, i.e. for each node
                                    that meets all of the scheduling requirements
                                    (resource request, requiredDuringScheduling affinity
                                    expressions, etc.), compute a sum by iterating
                                    through the elements of this field and adding
                                    "weight" to the sum if the node has pods which
                                    matches the corresponding podAffinityTerm; the
                                    node(s) with the highest sum are the most preferred.
                                  items:
                                    description: The weights of all of the matched
                                      WeightedPodAffinityTerm fields are added per-node
                                      to find the most preferred node(s)
                                    properties:
                                      podAffinityTerm:
                                        description: Required. A pod affinity term,
                                          associated with the corresponding weight.
                                        properties:
                                          labelSelector:
                                            description: A label query over a set
                                              of resources, in this case pods.
                                            properties:
                                              matchExpressions:
                                                description: matchExpressions is a
                                                  list of label selector requirements.
                                                  The requirements are ANDed.
                                                items:
                                                  description: A label selector requirement
                                                    is a selector that contains values,
                                                    a key, and an operator that relates
                                                    the key and values.
                                                  properties:
                                                    key:
                                                      description: key is the label
                                                        key that the selector applies
                                                        to.
                                                      type: string
                                                    operator:
                                                      description: operator represents
                                                        a key's relationship to a
                                                        set of values. Valid operators
                                                        are In, NotIn, Exists and
                                                        DoesNotExist.
                                                      type: string
                                                    values:
                                                      description: values is an array
                                                        of string values. If the operator
                                                        is In or NotIn, the values
                                                        array must be non-empty. If
                                                        the operator is Exists or
                                                        DoesNotExist, the values array
                                                        must be empty. This array
                                                        is replaced during a strategic
                                                        merge patch.
                                                      items:
                                                        type: string
                                                      type: array
                                                  required:
                                                  - key
                                                  - operator
                                                  type: object
                                                type: array
                                              matchLabels:
                                                additionalProperties:
                                                  type: string
                                                description: matchLabels is a map
                                                  of {key,value} pairs. A single {key,value}
                                                  in the matchLabels map is equivalent
                                                  to an element of matchExpressions,
                                                  whose key field is "key", the operator
                                                  is "In", and the values array contains
                                                  only "value". The requirements are
                                                  ANDed.
                                                type: object
                                            type: object
                                          namespaces:
                                            description: namespaces specifies which
                                              namespaces the labelSelector applies
                                              to (matches against); null or empty
                                              list means "this pod's namespace"
                                            items:
                                              type: string
                                            type: array
                                          topologyKey:
                                            description: This pod should be co-located
                                              (affinity) or not co-located (anti-affinity)
                                              with the pods matching the labelSelector
                                              in the specified namespaces, where co-located
                                              is defined as running on a node whose
                                              value of the label with key topologyKey
                                              matches that of any node on which any
                                              of the selected pods is running. Empty
                                              topologyKey is not allowed.
                                            type: string
                                        required:
                                        - topologyKey
                                        type: object
                                      weight:
                                        description: weight associated with matching
                                          the corresponding podAffinityTerm, in the
                                          range 1-100.
                                        format: int32
                                        type: integer
                                    required:
                                    - podAffinityTerm
                                    - weight
                                    type: object
                                  type: array
                                requiredDuringSchedulingIgnoredDuringExecution:
                                  description: If the affinity requirements specified
                                    by this field are not met at scheduling time,
                                    the pod will not be scheduled onto the node. If
                                    the affinity requirements specified by this field
                                    cease to be met at some point during pod execution
                                    (e.g. due to a pod label update), the system may
                                    or may not try to eventually evict the pod from
                                    its node. When there are multiple elements, the
                                    lists of nodes corresponding to each podAffinityTerm
                                    are intersected, i.e. all terms must be satisfied.
                                  items:
                                    description: Defines a set of pods (namely those
                                      matching the labelSelector relative to the given
                                      namespace(s)) that this pod should be co-located
                                      (affinity) or not co-located (anti-affinity)
                                      with, where co-located is defined as running
                                      on a node whose value of the label with key
                                      <topologyKey> matches that of any node on which
                                      a pod of the set of pods is running
                                    properties:
                                      labelSelector:
                                        description: A label query over a set of resources,
                                          in this case pods.
                                        properties:
                                          matchExpressions:
                                            description: matchExpressions is a list
                                              of label selector requirements. The
                                              requirements are ANDed.
                                            items:
                                              description: A label selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: key is the label key
                                                    that the selector applies to.
                                                  type: string
                                                operator:
                                                  description: operator represents
                                                    a key's relationship to a set
                                                    of values. Valid operators are
                                                    In, NotIn, Exists and DoesNotExist.
                                                  type: string
                                                values:
                                                  description: values is an array
                                                    of string values. If the operator
                                                    is In or NotIn, the values array
                                                    must be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. This
                                                    array is replaced during a strategic
                                                    merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                          matchLabels:
                                            additionalProperties:
                                              type: string
                                            description: matchLabels is a map of {key,value}
                                              pairs. A single {key,value} in the matchLabels
                                              map is equivalent to an element of matchExpressions,
                                              whose key field is "key", the operator
                                              is "In", and the values array contains
                                              only "value". The requirements are ANDed.
                                            type: object
                                        type: object
                                      namespaces:
                                        description: namespaces specifies which namespaces
                                          the labelSelector applies to (matches against);
                                          null or empty list means "this pod's namespace"
                                        items:
                                          type: string
                                        type: array
                                      topologyKey:
                                        description: This pod should be co-located
                                          (affinity) or not co-located (anti-affinity)
                                          with the pods matching the labelSelector
                                          in the specified namespaces, where co-located
                                          is defined as running on a node whose value
                                          of the label with key topologyKey matches
                                          that of any node on which any of the selected
                                          pods is running. Empty topologyKey is not
                                          allowed.
                                        type: string
                                    required:
                                    - topologyKey
                                    type: object
                                  type: array
                              type: object
                            podAntiAffinity:
                              description: Describes pod anti-affinity scheduling
                                rules (e.g. avoid putting this pod in the same node,
                                zone, etc. as some other pod(s)).
                              properties:
                                preferredDuringSchedulingIgnoredDuringExecution:
                                  description: The scheduler will prefer to schedule
                                    pods to nodes that satisfy the anti-affinity expressions
                                    specified by this field, but it may choose a node
                                    that violates one or more of the expressions.
                                    The node that is most preferred is the one with
                                    the greatest sum of weights, i.e. for each node
                                    that meets all of the scheduling requirements
                                    (resource request, requiredDuringScheduling anti-affinity
                                    expressions, etc.), compute a sum by iterating
                                    through the elements of this field and adding
                                    "weight" to the sum if the node has pods which
                                    matches the corresponding podAffinityTerm; the
                                    node(s) with the highest sum are the most preferred.
                                  items:
                                    description: The weights of all of the matched
                                      WeightedPodAffinityTerm fields are added per-node
                                      to find the most preferred node(s)
                                    properties:
                                      podAffinityTerm:
                                        description: Required. A pod affinity term,
                                          associated with the corresponding weight.
                                        properties:
                                          labelSelector:
                                            description: A label query over a set
                                              of resources, in this case pods.
                                            properties:
                                              matchExpressions:
                                                description: matchExpressions is a
                                                  list of label selector requirements.
                                                  The requirements are ANDed.
                                                items:
                                                  description: A label selector requirement
                                                    is a selector that contains values,
                                                    a key, and an operator that relates
                                                    the key and values.
                                                  properties:
                                                    key:
                                                      description: key is the label
                                                        key that the selector applies
                                                        to.
                                                      type: string
                                                    operator:
                                                      description: operator represents
                                                        a key's relationship to a
                                                        set of values. Valid operators
                                                        are In, NotIn, Exists and
                                                        DoesNotExist.
                                                      type: string
                                                    values:
                                                      description: values is an array
                                                        of string values. If the operator
                                                        is In or NotIn, the values
                                                        array must be non-empty. If
                                                        the operator is Exists or
                                                        DoesNotExist, the values array
                                                        must be empty. This array
                                                        is replaced during a strategic
                                                        merge patch.
                                                      items:
                                                        type: string
                                                      type: array
                                                  required:
                                                  - key
                                                  - operator
                                                  type: object
                                                type: array
                                              matchLabels:
                                                additionalProperties:
                                                  type: string
                                                description: matchLabels is a map
                                                  of {key,value} pairs. A single {key,value}
                                                  in the matchLabels map is equivalent
                                                  to an element of matchExpressions,
                                                  whose key field is "key", the operator
                                                  is "In", and the values array contains
                                                  only "value". The requirements are
                                                  ANDed.
                                                type: object
                                            type: object
                                          namespaces:
                                            description: namespaces specifies which
                                              namespaces the labelSelector applies
                                              to (matches against); null or empty
                                              list means "this pod's namespace"
                                            items:
                                              type: string
                                            type: array
                                          topologyKey:
                                            description: This pod should be co-located
                                              (affinity) or not co-located (anti-affinity)
                                              with the pods matching the labelSelector
                                              in the specified namespaces, where co-located
                                              is defined as running on a node whose
                                              value of the label with key topologyKey
                                              matches that of any node on which any
                                              of the selected pods is running. Empty
                                              topologyKey is not allowed.
                                            type: string
                                        required:
                                        - topologyKey
                                        type: object
                                      weight:
                                        description: weight associated with matching
                                          the corresponding podAffinityTerm, in the
                                          range 1-100.
                                        format: int32
                                        type: integer
                                    required:
                                    - podAffinityTerm
                                    - weight
                                    type: object
                                  type: array
                                requiredDuringSchedulingIgnoredDuringExecution:
                                  description: If the anti-affinity requirements specified
                                    by this field are not met at scheduling time,
                                    the pod will not be scheduled onto the node. If
                                    the anti-affinity requirements specified by this
                                    field cease to be met at some point during pod
                                    execution (e.g. due to a pod label update), the
                                    system may or may not try to eventually evict
                                    the pod from its node. When there are multiple
                                    elements, the lists of nodes corresponding to
                                    each podAffinityTerm are intersected, i.e. all
                                    terms must be satisfied.
                                  items:
                                    description: Defines a set of pods (namely those
                                      matching the labelSelector relative to the given
                                      namespace(s)) that this pod should be co-located
                                      (affinity) or not co-located (anti-affinity)
                                      with, where co-located is defined as running
                                      on a node whose value of the label with key
                                      <topologyKey> matches that of any node on which
                                      a pod of the set of pods is running
                                    properties:
                                      labelSelector:
                                        description: A label query over a set of resources,
                                          in this case pods.
                                        properties:
                                          matchExpressions:
                                            description: matchExpressions is a list
                                              of label selector requirements. The
                                              requirements are ANDed.
                                            items:
                                              description: A label selector requirement
                                                is a selector that contains values,
                                                a key, and an operator that relates
                                                the key and values.
                                              properties:
                                                key:
                                                  description: key is the label key
                                                    that the selector applies to.
                                                  type: string
                                                operator:
                                                  description: operator represents
                                                    a key's relationship to a set
                                                    of values. Valid operators are
                                                    In, NotIn, Exists and DoesNotExist.
                                                  type: string
                                                values:
                                                  description: values is an array
                                                    of string values. If the operator
                                                    is In or NotIn, the values array
                                                    must be non-empty. If the operator
                                                    is Exists or DoesNotExist, the
                                                    values array must be empty. This
                                                    array is replaced during a strategic
                                                    merge patch.
                                                  items:
                                                    type: string
                                                  type: array
                                              required:
                                              - key
                                              - operator
                                              type: object
                                            type: array
                                          matchLabels:
                                            additionalProperties:
                                              type: string
                                            description: matchLabels is a map of {key,value}
                                              pairs. A single {key,value} in the matchLabels
                                              map is equivalent to an element of matchExpressions,
                                              whose key field is "key", the operator
                                              is "In", and the values array contains
                                              only "value". The requirements are ANDed.
                                            type: object
                                        type: object
                                      namespaces:
                                        description: namespaces specifies which namespaces
                                          the labelSelector applies to (matches against);
                                          null or empty list means "this pod's namespace"
                                        items:
                                          type: string
                                        type: array
                                      topologyKey:
                                        description: This pod should be co-located
                                          (affinity) or not co-located (anti-affinity)
                                          with the pods matching the labelSelector
                                          in the specified namespaces, where co-located
                                          is defined as running on a node whose value
                                          of the label with key topologyKey matches
                                          that of any node on which any of the selected
                                          pods is running. Empty topologyKey is not
                                          allowed.
                                        type: string
                                    required:
                                    - topologyKey
                                    type: object
                                  type: array
                              type: object
                          type: object
                        automountServiceAccountToken:
                          description: AutomountServiceAccountToken indicates whether
                            a service account token should be automatically mounted.
                          type: boolean
                        containers:
                          description: List of containers belonging to the pod. Containers
                            cannot currently be added or removed. There must be at
                            least one container in a Pod. Cannot be updated.
                          items:
                            description: A single application container that you want
                              to run within a pod.
                            properties:
                              args:
                                description: 'Arguments to the entrypoint. The docker
                                  image''s CMD is used if this is not provided. Variable
                                  references $(VAR_NAME) are expanded using the container''s
                                  environment. If a variable cannot be resolved, the
                                  reference in the input string will be unchanged.
                                  The $(VAR_NAME) syntax can be escaped with a double
                                  $$, ie: $$(VAR_NAME). Escaped references will never
                                  be expanded, regardless of whether the variable
                                  exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
                                items:
                                  type: string
                                type: array
                              command:
                                description: 'Entrypoint array. Not executed within
                                  a shell. The docker image''s ENTRYPOINT is used
                                  if this is not provided. Variable references $(VAR_NAME)
                                  are expanded using the container''s environment.
                                  If a variable cannot be resolved, the reference
                                  in the input string will be unchanged. The $(VAR_NAME)
                                  syntax can be escaped with a double $$, ie: $$(VAR_NAME).
                                  Escaped references will never be expanded, regardless
                                  of whether the variable exists or not. Cannot be
                                  updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
                                items:
                                  type: string
                                type: array
                              env:
                                description: List of environment variables to set
                                  in the container. Cannot be updated.
                                items:
                                  description: EnvVar represents an environment variable
                                    present in a Container.
                                  properties:
                                    name:
                                      description: Name of the environment variable.
                                        Must be a C_IDENTIFIER.
                                      type: string
                                    value:
                                      description: 'Variable references $(VAR_NAME)
                                        are expanded using the previous defined environment
                                        variables in the container and any service
                                        environment variables. If a variable cannot
                                        be resolved, the reference in the input string
                                        will be unchanged. The $(VAR_NAME) syntax
                                        can be escaped with a double $$, ie: $$(VAR_NAME).
                                        Escaped references will never be expanded,
                                        regardless of whether the variable exists
                                        or not. Defaults to "".'
                                      type: string
                                    valueFrom:
                                      description: Source for the environment variable's
                                        value. Cannot be used if value is not empty.
                                      properties:
                                        configMapKeyRef:
                                          description: Selects a key of a ConfigMap.
                                          properties:
                                            key:
                                              description: The key to select.
                                              type: string
                                            name:
                                              description: 'Name of the referent.
                                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                                TODO: Add other useful fields. apiVersion,
                                                kind, uid?'
                                              type: string
                                            optional:
                                              description: Specify whether the ConfigMap
                                                or its key must be defined
                                              type: boolean
                                          required:
                                          - key
                                          type: object
                                        fieldRef:
                                          description: 'Selects a field of the pod:
                                            supports metadata.name, metadata.namespace,
                                            metadata.labels, metadata.annotations,
                                            spec.nodeName, spec.serviceAccountName,
                                            status.hostIP, status.podIP, status.podIPs.'
                                          properties:
                                            apiVersion:
                                              description: Version of the schema the
                                                FieldPath is written in terms of,
                                                defaults to "v1".
                                              type: string
                                            fieldPath:
                                              description: Path of the field to select
                                                in the specified API version.
                                              type: string
                                          required:
                                          - fieldPath
                                          type: object
                                        resourceFieldRef:
                                          description: 'Selects a resource of the
                                            container: only resources limits and requests
                                            (limits.cpu, limits.memory, limits.ephemeral-storage,
                                            requests.cpu, requests.memory and requests.ephemeral-storage)
                                            are currently supported.'
                                          properties:
                                            containerName:
                                              description: 'Container name: required
                                                for volumes, optional for env vars'
                                              type: string
                                            divisor:
                                              anyOf:
                                              - type: integer
                                              - type: string
                                              description: Specifies the output format
                                                of the exposed resources, defaults
                                                to "1"
                                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                              x-kubernetes-int-or-string: true
                                            resource:
                                              description: 'Required: resource to
                                                select'
                                              type: string
                                          required:
                                          - resource
                                          type: object
                                        secretKeyRef:
                                          description: Selects a key of a secret in
                                            the pod's namespace
                                          properties:
                                            key:
                                              description: The key of the secret to
                                                select from.  Must be a valid secret
                                                key.
                                              type: string
                                            name:
                                              description: 'Name of the referent.
                                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                                TODO: Add other useful fields. apiVersion,
                                                kind, uid?'
                                              type: string
                                            optional:
                                              description: Specify whether the Secret
                                                or its key must be defined
                                              type: boolean
                                          required:
                                          - key
                                          type: object
                                      type: object
                                  required:
                                  - name
                                  type: object
                                type: array
                              envFrom:
                                description: List of sources to populate environment
                                  variables in the container. The keys defined within
                                  a source must be a C_IDENTIFIER. All invalid keys
                                  will be reported as an event when the container
                                  is starting. When a key exists in multiple sources,
                                  the value associated with the last source will take
                                  precedence. Values defined by an Env with a duplicate
                                  key will take precedence. Cannot be updated.
                                items:
                                  description: EnvFromSource represents the source
                                    of a set of ConfigMaps
                                  properties:
                                    configMapRef:
                                      description: The ConfigMap to select from
                                      properties:
                                        name:
                                          description: 'Name of the referent. More
                                            info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                            TODO: Add other useful fields. apiVersion,
                                            kind, uid?'
                                          type: string
                                        optional:
                                          description: Specify whether the ConfigMap
                                            must be defined
                                          type: boolean
                                      type: object
                                    prefix:
                                      description: An optional identifier to prepend
                                        to each key in the ConfigMap. Must be a C_IDENTIFIER.
                                      type: string
                                    secretRef:
                                      description: The Secret to select from
                                      properties:
                                        name:
                                          description: 'Name of the referent. More
                                            info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                            TODO: Add other useful fields. apiVersion,
                                            kind, uid?'
                                          type: string
                                        optional:
                                          description: Specify whether the Secret
                                            must be defined
                                          type: boolean
                                      type: object
                                  type: object
                                type: array
                              image:
                                description: 'Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images
                                  This field is optional to allow higher level config
                                  management to default or override container images
                                  in workload controllers like Deployments and StatefulSets.'
                                type: string
                              imagePullPolicy:
                                description: 'Image pull policy. One of Always, Never,
                                  IfNotPresent. Defaults to Always if :latest tag
                                  is specified, or IfNotPresent otherwise. Cannot
                                  be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
                                type: string
                              lifecycle:
                                description: Actions that the management system should
                                  take in response to container lifecycle events.
                                  Cannot be updated.
                                properties:
                                  postStart:
                                    description: 'PostStart is called immediately
                                      after a container is created. If the handler
                                      fails, the container is terminated and restarted
                                      according to its restart policy. Other management
                                      of the container blocks until the hook completes.
                                      More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
                                    properties:
                                      exec:
                                        description: One and only one of the following
                                          should be specified. Exec specifies the
                                          action to take.
                                        properties:
                                          command:
                                            description: Command is the command line
                                              to execute inside the container, the
                                              working directory for the command  is
                                              root ('/') in the container's filesystem.
                                              The command is simply exec'd, it is
                                              not run inside a shell, so traditional
                                              shell instructions ('|', etc) won't
                                              work. To use a shell, you need to explicitly
                                              call out to that shell. Exit status
                                              of 0 is treated as live/healthy and
                                              non-zero is unhealthy.
                                            items:
                                              type: string
                                            type: array
                                        type: object
                                      httpGet:
                                        description: HTTPGet specifies the http request
                                          to perform.
                                        properties:
                                          host:
                                            description: Host name to connect to,
                                              defaults to the pod IP. You probably
                                              want to set "Host" in httpHeaders instead.
                                            type: string
                                          httpHeaders:
                                            description: Custom headers to set in
                                              the request. HTTP allows repeated headers.
                                            items:
                                              description: HTTPHeader describes a
                                                custom header to be used in HTTP probes
                                              properties:
                                                name:
                                                  description: The header field name
                                                  type: string
                                                value:
                                                  description: The header field value
                                                  type: string
                                              required:
                                              - name
                                              - value
                                              type: object
                                            type: array
                                          path:
                                            description: Path to access on the HTTP
                                              server.
                                            type: string
                                          port:
                                            anyOf:
                                            - type: integer
                                            - type: string
                                            description: Name or number of the port
                                              to access on the container. Number must
                                              be in the range 1 to 65535. Name must
                                              be an IANA_SVC_NAME.
                                            x-kubernetes-int-or-string: true
                                          scheme:
                                            description: Scheme to use for connecting
                                              to the host. Defaults to HTTP.
                                            type: string
                                        required:
                                        - port
                                        type: object
                                      tcpSocket:
                                        description: 'TCPSocket specifies an action
                                          involving a TCP port. TCP hooks not yet
                                          supported TODO: implement a realistic TCP
                                          lifecycle hook'
                                        properties:
                                          host:
                                            description: 'Optional: Host name to connect
                                              to, defaults to the pod IP.'
                                            type: string
                                          port:
                                            anyOf:
                                            - type: integer
                                            - type: string
                                            description: Number or name of the port
                                              to access on the container. Number must
                                              be in the range 1 to 65535. Name must
                                              be an IANA_SVC_NAME.
                                            x-kubernetes-int-or-string: true
                                        required:
                                        - port
                                        type: object
                                    type: object
                                  preStop:
                                    description: 'PreStop is called immediately before
                                      a container is terminated due to an API request
                                      or management event such as liveness/startup
                                      probe failure, preemption, resource contention,
                                      etc. The handler is not called if the container
                                      crashes or exits. The reason for termination
                                      is passed to the handler. The Pod''s termination
                                      grace period countdown begins before the PreStop
                                      hooked is executed. Regardless of the outcome
                                      of the handler, the container will eventually
                                      terminate within the Pod''s termination grace
                                      period. Other management of the container blocks
                                      until the hook completes or until the termination
                                      grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
                                    properties:
                                      exec:
                                        description: One and only one of the following
                                          should be specified. Exec specifies the
                                          action to take.
                                        properties:
                                          command:
                                            description: Command is the command line
                                              to execute inside the container, the
                                              working directory for the command  is
                                              root ('/') in the container's filesystem.
                                              The command is simply exec'd, it is
                                              not run inside a shell, so traditional
                                              shell instructions ('|', etc) won't
                                              work. To use a shell, you need to explicitly
                                              call out to that shell. Exit status
                                              of 0 is treated as live/healthy and
                                              non-zero is unhealthy.
                                            items:
                                              type: string
                                            type: array
                                        type: object
                                      httpGet:
                                        description: HTTPGet specifies the http request
                                          to perform.
                                        properties:
                                          host:
                                            description: Host name to connect to,
                                              defaults to the pod IP. You probably
                                              want to set "Host" in httpHeaders instead.
                                            type: string
                                          httpHeaders:
                                            description: Custom headers to set in
                                              the request. HTTP allows repeated headers.
                                            items:
                                              description: HTTPHeader describes a
                                                custom header to be used in HTTP probes
                                              properties:
                                                name:
                                                  description: The header field name
                                                  type: string
                                                value:
                                                  description: The header field value
                                                  type: string
                                              required:
                                              - name
                                              - value
                                              type: object
                                            type: array
                                          path:
                                            description: Path to access on the HTTP
                                              server.
                                            type: string
                                          port:
                                            anyOf:
                                            - type: integer
                                            - type: string
                                            description: Name or number of the port
                                              to access on the container. Number must
                                              be in the range 1 to 65535. Name must
                                              be an IANA_SVC_NAME.
                                            x-kubernetes-int-or-string: true
                                          scheme:
                                            description: Scheme to use for connecting
                                              to the host. Defaults to HTTP.
                                            type: string
                                        required:
                                        - port
                                        type: object
                                      tcpSocket:
                                        description: 'TCPSocket specifies an action
                                          involving a TCP port. TCP hooks not yet
                                          supported TODO: implement a realistic TCP
                                          lifecycle hook'
                                        properties:
                                          host:
                                            description: 'Optional: Host name to connect
                                              to, defaults to the pod IP.'
                                            type: string
                                          port:
                                            anyOf:
                                            - type: integer
                                            - type: string
                                            description: Number or name of the port
                                              to access on the container. Number must
                                              be in the range 1 to 65535. Name must
                                              be an IANA_SVC_NAME.
                                            x-kubernetes-int-or-string: true
                                        required:
                                        - port
                                        type: object
                                    type: object
                                type: object
                              livenessProbe:
                                description: 'Periodic probe of container liveness.
                                  Container will be restarted if the probe fails.
                                  Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                properties:
                                  exec:
                                    description: One and only one of the following
                                      should be specified. Exec specifies the action
                                      to take.
                                    properties:
                                      command:
                                        description: Command is the command line to
                                          execute inside the container, the working
                                          directory for the command  is root ('/')
                                          in the container's filesystem. The command
                                          is simply exec'd, it is not run inside a
                                          shell, so traditional shell instructions
                                          ('|', etc) won't work. To use a shell, you
                                          need to explicitly call out to that shell.
                                          Exit status of 0 is treated as live/healthy
                                          and non-zero is unhealthy.
                                        items:
                                          type: string
                                        type: array
                                    type: object
                                  failureThreshold:
                                    description: Minimum consecutive failures for
                                      the probe to be considered failed after having
                                      succeeded. Defaults to 3. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  httpGet:
                                    description: HTTPGet specifies the http request
                                      to perform.
                                    properties:
                                      host:
                                        description: Host name to connect to, defaults
                                          to the pod IP. You probably want to set
                                          "Host" in httpHeaders instead.
                                        type: string
                                      httpHeaders:
                                        description: Custom headers to set in the
                                          request. HTTP allows repeated headers.
                                        items:
                                          description: HTTPHeader describes a custom
                                            header to be used in HTTP probes
                                          properties:
                                            name:
                                              description: The header field name
                                              type: string
                                            value:
                                              description: The header field value
                                              type: string
                                          required:
                                          - name
                                          - value
                                          type: object
                                        type: array
                                      path:
                                        description: Path to access on the HTTP server.
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Name or number of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                      scheme:
                                        description: Scheme to use for connecting
                                          to the host. Defaults to HTTP.
                                        type: string
                                    required:
                                    - port
                                    type: object
                                  initialDelaySeconds:
                                    description: 'Number of seconds after the container
                                      has started before liveness probes are initiated.
                                      More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                  periodSeconds:
                                    description: How often (in seconds) to perform
                                      the probe. Default to 10 seconds. Minimum value
                                      is 1.
                                    format: int32
                                    type: integer
                                  successThreshold:
                                    description: Minimum consecutive successes for
                                      the probe to be considered successful after
                                      having failed. Defaults to 1. Must be 1 for
                                      liveness and startup. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  tcpSocket:
                                    description: 'TCPSocket specifies an action involving
                                      a TCP port. TCP hooks not yet supported TODO:
                                      implement a realistic TCP lifecycle hook'
                                    properties:
                                      host:
                                        description: 'Optional: Host name to connect
                                          to, defaults to the pod IP.'
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Number or name of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                    required:
                                    - port
                                    type: object
                                  timeoutSeconds:
                                    description: 'Number of seconds after which the
                                      probe times out. Defaults to 1 second. Minimum
                                      value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                type: object
                              name:
                                description: Name of the container specified as a
                                  DNS_LABEL. Each container in a pod must have a unique
                                  name (DNS_LABEL). Cannot be updated.
                                type: string
                              ports:
                                description: List of ports to expose from the container.
                                  Exposing a port here gives the system additional
                                  information about the network connections a container
                                  uses, but is primarily informational. Not specifying
                                  a port here DOES NOT prevent that port from being
                                  exposed. Any port which is listening on the default
                                  "0.0.0.0" address inside a container will be accessible
                                  from the network. Cannot be updated.
                                items:
                                  description: ContainerPort represents a network
                                    port in a single container.
                                  properties:
                                    containerPort:
                                      description: Number of port to expose on the
                                        pod's IP address. This must be a valid port
                                        number, 0 < x < 65536.
                                      format: int32
                                      type: integer
                                    hostIP:
                                      description: What host IP to bind the external
                                        port to.
                                      type: string
                                    hostPort:
                                      description: Number of port to expose on the
                                        host. If specified, this must be a valid port
                                        number, 0 < x < 65536. If HostNetwork is specified,
                                        this must match ContainerPort. Most containers
                                        do not need this.
                                      format: int32
                                      type: integer
                                    name:
                                      description: If specified, this must be an IANA_SVC_NAME
                                        and unique within the pod. Each named port
                                        in a pod must have a unique name. Name for
                                        the port that can be referred to by services.
                                      type: string
                                    protocol:
                                      description: Protocol for port. Must be UDP,
                                        TCP, or SCTP. Defaults to "TCP".
                                      type: string
                                  required:
                                  - containerPort
                                  - protocol
                                  type: object
                                type: array
                                x-kubernetes-list-map-keys:
                                - containerPort
                                - protocol
                                x-kubernetes-list-type: map
                              readinessProbe:
                                description: 'Periodic probe of container service
                                  readiness. Container will be removed from service
                                  endpoints if the probe fails. Cannot be updated.
                                  More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                properties:
                                  exec:
                                    description: One and only one of the following
                                      should be specified. Exec specifies the action
                                      to take.
                                    properties:
                                      command:
                                        description: Command is the command line to
                                          execute inside the container, the working
                                          directory for the command  is root ('/')
                                          in the container's filesystem. The command
                                          is simply exec'd, it is not run inside a
                                          shell, so traditional shell instructions
                                          ('|', etc) won't work. To use a shell, you
                                          need to explicitly call out to that shell.
                                          Exit status of 0 is treated as live/healthy
                                          and non-zero is unhealthy.
                                        items:
                                          type: string
                                        type: array
                                    type: object
                                  failureThreshold:
                                    description: Minimum consecutive failures for
                                      the probe to be considered failed after having
                                      succeeded. Defaults to 3. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  httpGet:
                                    description: HTTPGet specifies the http request
                                      to perform.
                                    properties:
                                      host:
                                        description: Host name to connect to, defaults
                                          to the pod IP. You probably want to set
                                          "Host" in httpHeaders instead.
                                        type: string
                                      httpHeaders:
                                        description: Custom headers to set in the
                                          request. HTTP allows repeated headers.
                                        items:
                                          description: HTTPHeader describes a custom
                                            header to be used in HTTP probes
                                          properties:
                                            name:
                                              description: The header field name
                                              type: string
                                            value:
                                              description: The header field value
                                              type: string
                                          required:
                                          - name
                                          - value
                                          type: object
                                        type: array
                                      path:
                                        description: Path to access on the HTTP server.
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Name or number of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                      scheme:
                                        description: Scheme to use for connecting
                                          to the host. Defaults to HTTP.
                                        type: string
                                    required:
                                    - port
                                    type: object
                                  initialDelaySeconds:
                                    description: 'Number of seconds after the container
                                      has started before liveness probes are initiated.
                                      More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                  periodSeconds:
                                    description: How often (in seconds) to perform
                                      the probe. Default to 10 seconds. Minimum value
                                      is 1.
                                    format: int32
                                    type: integer
                                  successThreshold:
                                    description: Minimum consecutive successes for
                                      the probe to be considered successful after
                                      having failed. Defaults to 1. Must be 1 for
                                      liveness and startup. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  tcpSocket:
                                    description: 'TCPSocket specifies an action involving
                                      a TCP port. TCP hooks not yet supported TODO:
                                      implement a realistic TCP lifecycle hook'
                                    properties:
                                      host:
                                        description: 'Optional: Host name to connect
                                          to, defaults to the pod IP.'
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Number or name of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                    required:
                                    - port
                                    type: object
                                  timeoutSeconds:
                                    description: 'Number of seconds after which the
                                      probe times out. Defaults to 1 second. Minimum
                                      value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                type: object
                              resources:
                                description: 'Compute Resources required by this container.
                                  Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
                                properties:
                                  limits:
                                    additionalProperties:
                                      anyOf:
                                      - type: integer
                                      - type: string
                                      pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                      x-kubernetes-int-or-string: true
                                    description: 'Limits describes the maximum amount
                                      of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
                                    type: object
                                  requests:
                                    additionalProperties:
                                      anyOf:
                                      - type: integer
                                      - type: string
                                      pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                      x-kubernetes-int-or-string: true
                                    description: 'Requests describes the minimum amount
                                      of compute resources required. If Requests is
                                      omitted for a container, it defaults to Limits
                                      if that is explicitly specified, otherwise to
                                      an implementation-defined value. More info:
                                      https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
                                    type: object
                                type: object
                              securityContext:
                                description: 'Security options the pod should run
                                  with. More info: https://kubernetes.io/docs/concepts/policy/security-context/
                                  More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
                                properties:
                                  allowPrivilegeEscalation:
                                    description: 'AllowPrivilegeEscalation controls
                                      whether a process can gain more privileges than
                                      its parent process. This bool directly controls
                                      if the no_new_privs flag will be set on the
                                      container process. AllowPrivilegeEscalation
                                      is true always when the container is: 1) run
                                      as Privileged 2) has CAP_SYS_ADMIN'
                                    type: boolean
                                  capabilities:
                                    description: The capabilities to add/drop when
                                      running containers. Defaults to the default
                                      set of capabilities granted by the container
                                      runtime.
                                    properties:
                                      add:
                                        description: Added capabilities
                                        items:
                                          description: Capability represent POSIX
                                            capabilities type
                                          type: string
                                        type: array
                                      drop:
                                        description: Removed capabilities
                                        items:
                                          description: Capability represent POSIX
                                            capabilities type
                                          type: string
                                        type: array
                                    type: object
                                  privileged:
                                    description: Run container in privileged mode.
                                      Processes in privileged containers are essentially
                                      equivalent to root on the host. Defaults to
                                      false.
                                    type: boolean
                                  procMount:
                                    description: procMount denotes the type of proc
                                      mount to use for the containers. The default
                                      is DefaultProcMount which uses the container
                                      runtime defaults for readonly paths and masked
                                      paths. This requires the ProcMountType feature
                                      flag to be enabled.
                                    type: string
                                  readOnlyRootFilesystem:
                                    description: Whether this container has a read-only
                                      root filesystem. Default is false.
                                    type: boolean
                                  runAsGroup:
                                    description: The GID to run the entrypoint of
                                      the container process. Uses runtime default
                                      if unset. May also be set in PodSecurityContext.  If
                                      set in both SecurityContext and PodSecurityContext,
                                      the value specified in SecurityContext takes
                                      precedence.
                                    format: int64
                                    type: integer
                                  runAsNonRoot:
                                    description: Indicates that the container must
                                      run as a non-root user. If true, the Kubelet
                                      will validate the image at runtime to ensure
                                      that it does not run as UID 0 (root) and fail
                                      to start the container if it does. If unset
                                      or false, no such validation will be performed.
                                      May also be set in PodSecurityContext.  If set
                                      in both SecurityContext and PodSecurityContext,
                                      the value specified in SecurityContext takes
                                      precedence.
                                    type: boolean
                                  runAsUser:
                                    description: The UID to run the entrypoint of
                                      the container process. Defaults to user specified
                                      in image metadata if unspecified. May also be
                                      set in PodSecurityContext.  If set in both SecurityContext
                                      and PodSecurityContext, the value specified
                                      in SecurityContext takes precedence.
                                    format: int64
                                    type: integer
                                  seLinuxOptions:
                                    description: The SELinux context to be applied
                                      to the container. If unspecified, the container
                                      runtime will allocate a random SELinux context
                                      for each container.  May also be set in PodSecurityContext.  If
                                      set in both SecurityContext and PodSecurityContext,
                                      the value specified in SecurityContext takes
                                      precedence.
                                    properties:
                                      level:
                                        description: Level is SELinux level label
                                          that applies to the container.
                                        type: string
                                      role:
                                        description: Role is a SELinux role label
                                          that applies to the container.
                                        type: string
                                      type:
                                        description: Type is a SELinux type label
                                          that applies to the container.
                                        type: string
                                      user:
                                        description: User is a SELinux user label
                                          that applies to the container.
                                        type: string
                                    type: object
                                  windowsOptions:
                                    description: The Windows specific settings applied
                                      to all containers. If unspecified, the options
                                      from the PodSecurityContext will be used. If
                                      set in both SecurityContext and PodSecurityContext,
                                      the value specified in SecurityContext takes
                                      precedence.
                                    properties:
                                      gmsaCredentialSpec:
                                        description: GMSACredentialSpec is where the
                                          GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa)
                                          inlines the contents of the GMSA credential
                                          spec named by the GMSACredentialSpecName
                                          field.
                                        type: string
                                      gmsaCredentialSpecName:
                                        description: GMSACredentialSpecName is the
                                          name of the GMSA credential spec to use.
                                        type: string
                                      runAsUserName:
                                        description: The UserName in Windows to run
                                          the entrypoint of the container process.
                                          Defaults to the user specified in image
                                          metadata if unspecified. May also be set
                                          in PodSecurityContext. If set in both SecurityContext
                                          and PodSecurityContext, the value specified
                                          in SecurityContext takes precedence.
                                        type: string
                                    type: object
                                type: object
                              startupProbe:
                                description: 'StartupProbe indicates that the Pod
                                  has successfully initialized. If specified, no other
                                  probes are executed until this completes successfully.
                                  If this probe fails, the Pod will be restarted,
                                  just as if the livenessProbe failed. This can be
                                  used to provide different probe parameters at the
                                  beginning of a Pod''s lifecycle, when it might take
                                  a long time to load data or warm a cache, than during
                                  steady-state operation. This cannot be updated.
                                  This is a beta feature enabled by the StartupProbe
                                  feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                properties:
                                  exec:
                                    description: One and only one of the following
                                      should be specified. Exec specifies the action
                                      to take.
                                    properties:
                                      command:
                                        description: Command is the command line to
                                          execute inside the container, the working
                                          directory for the command  is root ('/')
                                          in the container's filesystem. The command
                                          is simply exec'd, it is not run inside a
                                          shell, so traditional shell instructions
                                          ('|', etc) won't work. To use a shell, you
                                          need to explicitly call out to that shell.
                                          Exit status of 0 is treated as live/healthy
                                          and non-zero is unhealthy.
                                        items:
                                          type: string
                                        type: array
                                    type: object
                                  failureThreshold:
                                    description: Minimum consecutive failures for
                                      the probe to be considered failed after having
                                      succeeded. Defaults to 3. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  httpGet:
                                    description: HTTPGet specifies the http request
                                      to perform.
                                    properties:
                                      host:
                                        description: Host name to connect to, defaults
                                          to the pod IP. You probably want to set
                                          "Host" in httpHeaders instead.
                                        type: string
                                      httpHeaders:
                                        description: Custom headers to set in the
                                          request. HTTP allows repeated headers.
                                        items:
                                          description: HTTPHeader describes a custom
                                            header to be used in HTTP probes
                                          properties:
                                            name:
                                              description: The header field name
                                              type: string
                                            value:
                                              description: The header field value
                                              type: string
                                          required:
                                          - name
                                          - value
                                          type: object
                                        type: array
                                      path:
                                        description: Path to access on the HTTP server.
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Name or number of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                      scheme:
                                        description: Scheme to use for connecting
                                          to the host. Defaults to HTTP.
                                        type: string
                                    required:
                                    - port
                                    type: object
                                  initialDelaySeconds:
                                    description: 'Number of seconds after the container
                                      has started before liveness probes are initiated.
                                      More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                  periodSeconds:
                                    description: How often (in seconds) to perform
                                      the probe. Default to 10 seconds. Minimum value
                                      is 1.
                                    format: int32
                                    type: integer
                                  successThreshold:
                                    description: Minimum consecutive successes for
                                      the probe to be considered successful after
                                      having failed. Defaults to 1. Must be 1 for
                                      liveness and startup. Minimum value is 1.
                                    format: int32
                                    type: integer
                                  tcpSocket:
                                    description: 'TCPSocket specifies an action involving
                                      a TCP port. TCP hooks not yet supported TODO:
                                      implement a realistic TCP lifecycle hook'
                                    properties:
                                      host:
                                        description: 'Optional: Host name to connect
                                          to, defaults to the pod IP.'
                                        type: string
                                      port:
                                        anyOf:
                                        - type: integer
                                        - type: string
                                        description: Number or name of the port to
                                          access on the container. Number must be
                                          in the range 1 to 65535. Name must be an
                                          IANA_SVC_NAME.
                                        x-kubernetes-int-or-string: true
                                    required:
                                    - port
                                    type: object
                                  timeoutSeconds:
                                    description: 'Number of seconds after which the
                                      probe times out. Defaults to 1 second. Minimum
                                      value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
                                    format: int32
                                    type: integer
                                type: object
                              stdin:
                                description: Whether this container should allocate
                                  a buffer for stdin in the container runtime. If
                                  this is not set, reads from stdin in the container
                                  will always result in EOF. Default is false.
                                type: boolean
                              stdinOnce:
                                description: Whether the container runtime should
                                  close the stdin channel after it has been opened
                                  by a single attach. When stdin is true the stdin
                                  stream will remain open across multiple attach sessions.
                                  If stdinOnce is set to true, stdin is opened on
                                  container start, is empty until the first client
                                  attaches to stdin, and then remains open and accepts
                                  data until the client disconnects, at which time
                                  stdin is closed and remains closed until the container
                                  is restarted. If this flag is false, a container
                                  processes that reads from stdin will never receive
                                  an EOF. Default is false
                                type: boolean
                              terminationMessagePath:
                                description: 'Optional: Path at which the file to
                                  which the container''s termination message will
                                  be written is mounted into the container''s filesystem.
                                  Message written is intended to be brief final status,
                                  such as an assertion failure message. Will be truncated
                                  by the node if greater than 4096 bytes. The total
                                  message length across all containers will be limited
                                  to 12kb. Defaults to /dev/termination-log. Cannot
                                  be updated.'
                                type: string
                              terminationMessagePolicy:
                                description: Indicate how the termination message
                                  should be populated. File will use the contents
                                  of terminationMessagePath to populate the container
                                  status message on both success and failure. FallbackToLogsOnError
                                  will use the last chunk of container log output
                                  if the termination message file is empty and the
                                  container exited with an error. The log output is
                                  limited to 2048 bytes or 80 lines, whichever is
                                  smaller. Defaults to File. Cannot be updated.
                                type: string
                              tty:
                                description: Whether this container should allocate
                                  a TTY for itself, also requires 'stdin' to be true.
                                  Default is false.
                                type: boolean
                              volumeDevices:
                                description: volumeDevices is the list of block devices
                                  to be used by the container.
                                items:
                                  description: volumeDevice describes a mapping of
                                    a raw block device within a container.
                                  properties:
                                    devicePath:
                                      description: devicePath is the path inside of
                                        the container that the device will be mapped
                                        to.
                                      type: string
                                    name:
                                      description: name must match the name of a persistentVolumeClaim
                                        in the pod
                                      type: string
                                  required:
                                  - devicePath
                                  - name
                                  type: object
                                type: array
                              volumeMounts:
                                description: Pod volumes to mount into the container's
                                  filesystem. Cannot be updated.
                                items:
                                  description: VolumeMount describes a mounting of
                                    a Volume within a container.
                                  properties:
                                    mountPath:
                                      description: Path within the container at which
                                        the volume should be mounted.  Must not contain
                                        ':'.
                                      type: string
                                    mountPropagation:
                                      description: mountPropagation determines how
                                        mounts are propagated from the host to container
                                        and the other way around. When not set, MountPropagationNone
                                        is used. This field is beta in 1.10.
                                      type: string
                                    name:
                                      description: This must match the Name of a Volume.
                                      type: string
                                    readOnly:
                                      description: Mounted read-only if true, read-write
                                        otherwise (false or unspecified). Defaults
                                        to false.
                                      type: boolean
                                    subPath:
                                      description: Path within the volume from which
                                        the container's volume should be mounted.
                                        Defaults to "" (volume's root).
                                      type: string
                                    subPathExpr:
                                      description: Expanded path within the volume
                                        from which the container's volume should be
                                        mounted. Behaves similarly to SubPath but
                                        environment variable references $(VAR_NAME)
                                        are expanded using the container's environment.
                                        Defaults to "" (volume's root). SubPathExpr
                                        and SubPath are mutually exclusive.
                                      type: string
                                  required:
                                  - mountPath
                                  - name
                                  type: object
                                type: array
                              workingDir:
                                description: Container's working directory. If not
                                  specified, the container runtime's default will
                                  be used, which might be configured in the container
                                  image. Cannot be updated.
                                type: string
                            required:
                            - name
                            type: object
                          type: array
                        dnsConfig:
                          description: Specifies the DNS parameters of a pod. Parameters
                            specified here will be merged to the generated DNS configuration
                            based on DNSPolicy.
                          properties:
                            nameservers:
                              description: A list of DNS name server IP addresses.
                                This will be appended to the base nameservers generated
                                from DNSPolicy. Duplicated nameservers will be removed.
                              items:
                                type: string
                              type: array
                            options:
                              description: A list of DNS resolver options. This will
                                be merged with the base options generated from DNSPolicy.
                                Duplicated entries will be removed. Resolution options
                                given in Options will override those that appear in
                                the base DNSPolicy.
                              items:
                                description: PodDNSConfigOption defines DNS resolver
                                  options of a pod.
                                properties:
                                  name:
                                    description: Required.
                                    type: string
                                  value:
                                    type: string
                                type: object
                              type: array
                            searches:
                              description: A list of DNS search domains for host-name
                                lookup. This will be appended to the base search paths
                                generated from DNSPolicy. Duplicated search paths
                                will be removed.
                              items:
                                type: string
                              type: array
                          type: object
                        dnsPolicy:
                          description: Set DNS policy for the pod. Defaults to "ClusterFirst".
                            Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst',
                            'Default' or 'None'. DNS parameters given in DNSConfig
                            will be merged with the policy selected with DNSPolicy.
                            To have DNS options set along with hostNetwork, you have
                            to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
                          type: string
                        enableServiceLinks:
                          description: 'EnableServiceLinks indicates whether information
                            about services should be injected into pod''s environment
                            variables, matching the syntax of Docker links. Optional:
                            Defaults to true.'
                          type: boolean
                        ephemeralContainers:
                          description: List of ephemeral containers run in this pod.
                            Ephemeral containers may be run in an existing pod to
                            perform user-initiated actions such as debugging. This
                            list cannot be specified when creating a pod, and it cannot
                            be modified by updating the pod spec. In order to add
                            an ephemeral container to an existing pod, use the pod's
                            ephemeralcontainers subresource. This field is alpha-level
                            and is only honored by servers that enable the EphemeralContainers
                            feature.
                          items:
                            description: An EphemeralContainer is a container that
                              may be added temporarily to an existing pod for user-initiated
                              activities such as debugging. Ephemeral containers have
                              no resource or scheduling guarantees, and they will
                              not be restarted when they exit or when a pod is removed
                              or restarted. If an ephemeral container causes a pod
                              to exceed its resource allocation, the pod may be evicted.
                              Ephemeral containers may not be added by directly updating
                              the pod spec. They must be added via the pod's ephemeralcontainers
                              subresource, and they will appear in the pod spec once
                              added. This is an alpha feature enabled by the EphemeralContainers
                              feature flag.
                            properties:
                              args:
                                description: 'Arguments to the entrypoint. The docker
                                  image''s CMD is used if this is not provided. Variable
                                  references $(VAR_NAME) are expanded using the container''s
                                  environment. If a variable cannot be resolved, the
                                  reference in the input string will be unchanged.
                                  The $(VAR_NAME) syntax can be escaped with a double
                                  $$, ie: $$(VAR_NAME). Escaped references will never
                                  be expanded, regardless of whether the variable
                                  exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
                                items:
                                  type: string
                                type: array
                              command:
                                description: 'Entrypoint array. Not executed within
                                  a shell. The docker image''s ENTRYPOINT is used
                                  if this is not provided. Variable references $(VAR_NAME)
                                  are expanded using the container''s environment.
                                  If a variable cannot be resolved, the reference
                                  in the input string will be unchanged. The $(VAR_NAME)
                                  syntax can be escaped with a double $$, ie: $$(VAR_NAME).
                                  Escaped references will never be expanded, regardless
                                  of whether the variable exists or not. Cannot be
                                  updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
                                items:
                                  type: string
                                type: array
                              env:
                                description: List of environment variables to set
                                  in the container. Cannot be updated.
                                items:
                                  description: EnvVar represents an environment variable
                                    present in a Container.
                                  properties:
                                    name:
                                      description: Name of the environment variable.
                                        Must be a C_IDENTIFIER.
                                      type: string
                                    value:
                                      description: 'Variable references $(VAR_NAME)
                                        are expanded using the previous defined environment
                                        variables in the container and any service
                                        environment variables. If a variable cannot
                                        be resolved, the reference in the input string
                                        will be unchanged. The $(VAR_NAME) syntax
                                        can be escaped with a double $$, ie: $$(VAR_NAME).
                                        Escaped references will never be expanded,
                                        regardless of whether the variable exists
                                        or not. Defaults to "".'
                                      type: string
                                    valueFrom:
                                      description: Source for the environment variable's
                                        value. Cannot be used if value is not empty.
                                      properties:
                                        configMapKeyRef:
                                          description: Selects a key of a ConfigMap.
                                          properties:
                                            key:
                                              description: The key to select.
                                              type: string
                                            name:
                                              description: 'Name of the referent.
                                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                                TODO: Add other useful fields. apiVersion,
                                                kind, uid?'
                                              type: string
                                            optional:
                                              description: Specify whether the ConfigMap
                                                or its key must be defined
                                              type: boolean
                                          required:
                                          - key
                                          type: object
                                        fieldRef:
                                          description: 'Selects a field of the pod:
                                            supports metadata.name, metadata.namespace,
                                            metadata.labels, metadata.annotations,
                                            spec.nodeName, spec.serviceAccountName,
                                            status.hostIP, status.podIP, status.podIPs.'
                                          properties:
                                            apiVersion:
                                              description: Version of the schema the
                                                FieldPath is written in terms of,
                                                defaults to "v1".
                                              type: string
                                            fieldPath:
                                              description: Path of the field to select
                                                in the specified API version.
                                              type: string
                                          required:
                                          - fieldPath
                                          type: object
                                        resourceFieldRef:
                                          description: 'Selects a resource of the
                                            container: only resources limits and requests
                                            (limits.cpu, limits.memory, limits.ephemeral-storage,
                                            requests.cpu, requests.memory and requests.ephemeral-storage)
                                            are currently supported.'
                                          properties:
                                            containerName:
                                              description: 'Container name: required
                                                for volumes, optional for env vars'
                                              type: string
                                            divisor:
                                              anyOf:
                                              - type: integer
                                              - type: string
                                              description: Specifies the output format
                                                of the exposed resources, defaults
                                                to "1"
                                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                              x-kubernetes-int-or-string: true
                                            resource:
                                              description: 'Required: resource to
                                                select'
                                              type: string
                                          required:
                                          - resource
                                          type: object
                                        secretKeyRef:
                                          description: Selects a key of a secret in
                                            the pod's namespace
                                          properties:
                                            key:
                                              description: The key of the secret to
                                                select from.  Must be a valid secret
                                                key.
                                              type: string
                                            name:
                                              description: 'Name of the referent.
                                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                                TODO: Add other useful fields. apiVersion,
                                                kind, uid?'
                                              type: string
                                            optional:
                                              description: Specify whether the Secret
                                                or its key must be defined
                                              type: boolean
                                          required:
                                          - key
                                          type: object
                                      type: object
                                  required:
                                  - name
                                  type: object
                                type: array
                              envFrom:
                                description: List of sources to populate environment
                                  variables in the container. The keys defined within
                                  a source must be a C_IDENTIFIER. All invalid keys
                                  will be reported as an event when the container
                                  is starting. When a key exists in multiple sources,
                                  the value associated with the last source will take
                                  precedence. Values defined by an Env with a duplicate
                                  key will take precedence. Cannot be updated.
                                items:
                                  description: EnvFromSource represents the source
                                    of a set of ConfigMaps
                                  properties:
                                    configMapRef:
                                      description: The ConfigMap to select from
                                      properties:
                                        name:
                                          descriptio
Download .txt
gitextract_3z6jna8z/

├── .gitignore
├── LICENSE
├── README.md
├── apim-gateway/
│   ├── README.md
│   ├── apim/
│   │   ├── api.yaml
│   │   ├── policy-all.json
│   │   ├── policy-echo.json
│   │   ├── policy-message.json
│   │   └── policy-save.json
│   └── k8s/
│       ├── binding.yaml
│       ├── echo-service.yaml
│       ├── event-subscriber.yaml
│       ├── gateway.yaml
│       └── pubsub.yaml
├── autoscaling-on-queue/
│   ├── README.md
│   ├── deployment/
│   │   ├── kafka-client.yaml
│   │   ├── kafka-pubsub.yaml
│   │   ├── keda-2.0.0-beta.yaml
│   │   ├── producer.yaml
│   │   ├── subscriber-scaler.yaml
│   │   └── subscriber.yaml
│   ├── producer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── subscriber/
│       ├── Dockerfile
│       ├── Makefile
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── component-api/
│   ├── README.md
│   ├── config/
│   │   ├── email.yaml
│   │   ├── state.yaml
│   │   └── twitter.yaml
│   └── sample/
│       ├── email.json
│       └── twitter.json
├── cron-binding/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   └── cron.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── dapr-aci/
│   ├── README.md
│   ├── components/
│   │   ├── pubsub.yaml
│   │   └── state.yaml
│   ├── deployment/
│   │   └── app.yaml
│   └── src/
│       ├── Dockerfile
│       ├── Makefile
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── dapr-api-on-aci/
│   ├── README.md
│   └── email.yaml
├── daprized-ingress/
│   ├── README.md
│   └── config/
│       ├── ingress-annotations.yaml
│       ├── ingress-config.yaml
│       ├── ingress.yaml
│       └── namespace.yml
├── fan-out/
│   ├── README.md
│   ├── grpc-echo-service/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── deployment.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── http-format-converter/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── source-pubsub.yaml
│   │   │   └── target-binding.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── components.yaml
│   │   │   └── deployment.yaml
│   │   └── main.go
│   ├── queue-event-consumer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   └── source-pabusb.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   ├── queue-event-producer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   └── target-pabusb.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   ├── queue-format-converter/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── kafka.yaml
│   │   │   ├── source-pabusb.yaml
│   │   │   └── target-pubsub.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── k8s/
│   │   │   ├── deployment.yaml
│   │   │   ├── target-kafka.yaml
│   │   │   └── target-redis.yaml
│   │   └── main.go
│   └── service-format-converter/
│       ├── Dockerfile
│       ├── Makefile
│       ├── config/
│       │   └── source-pubsub.yaml
│       ├── go.mod
│       ├── go.sum
│       ├── k8s/
│       │   ├── components.yaml
│       │   └── deployment.yaml
│       └── main.go
├── grpc-echo-service/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── deployment/
│   │   ├── app.yaml
│   │   └── space.yaml
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── grpc-event-subscriber/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   └── pubsub.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── hardened/
│   ├── Makefile
│   ├── README.md
│   ├── config/
│   │   ├── pubsub.yaml
│   │   └── state.yaml
│   ├── deployment/
│   │   ├── hardened/
│   │   │   ├── app1.yaml
│   │   │   ├── app2.yaml
│   │   │   ├── app3.yaml
│   │   │   ├── pubsub.yaml
│   │   │   └── state.yaml
│   │   ├── namespace/
│   │   │   ├── ns.yaml
│   │   │   ├── role.yaml
│   │   │   └── trace.yaml
│   │   └── simple/
│   │       ├── app1.yaml
│   │       ├── app2.yaml
│   │       ├── app3.yaml
│   │       ├── pubsub.yaml
│   │       └── state.yaml
│   └── src/
│       ├── app1/
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── go.mod
│       │   ├── go.sum
│       │   └── main.go
│       ├── app2/
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── go.mod
│       │   ├── go.sum
│       │   └── main.go
│       └── app3/
│           ├── Dockerfile
│           ├── Makefile
│           ├── go.mod
│           ├── go.sum
│           └── main.go
├── http-echo-service/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── deployment.yaml
│   ├── go.mod
│   ├── go.sum
│   └── main.go
├── http-event-subscriber/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── clooudevent.json
│   ├── config/
│   │   └── pubsub.yaml
│   ├── go.mod
│   ├── go.sum
│   ├── k8s/
│   │   ├── component.yaml
│   │   └── deployment.yaml
│   └── main.go
├── order-cancellation/
│   ├── README.md
│   ├── demo/
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── component/
│   │   │   ├── audit-store.yaml
│   │   │   ├── email.yaml
│   │   │   ├── queue.yaml
│   │   │   └── workflow-store.yaml
│   │   ├── config/
│   │   │   └── order-cancel.json
│   │   ├── data/
│   │   │   ├── cancellation.json
│   │   │   ├── email.json
│   │   │   └── meta.json
│   │   └── deployment/
│   │       ├── auditor.yaml
│   │       ├── ingress.yaml
│   │       ├── space.yaml
│   │       ├── viewer.yaml
│   │       └── workflow.yaml
│   └── src/
│       ├── fn/
│       │   ├── .gitignore
│       │   ├── DaprAzFn.csproj
│       │   ├── Dockerfile
│       │   ├── Makefile
│       │   ├── ReceiveEvent.cs
│       │   ├── config/
│       │   │   ├── meta.json
│       │   │   ├── pubsub.yaml
│       │   │   └── statestore.yaml
│       │   ├── host.json
│       │   └── local.settings.json
│       └── viewer/
│           ├── Dockerfile
│           ├── Makefile
│           ├── config/
│           │   └── queue.yaml
│           ├── go.mod
│           ├── go.sum
│           ├── main.go
│           └── resource/
│               ├── static/
│               │   ├── css/
│               │   │   └── app.css
│               │   └── js/
│               │       └── app.js
│               └── template/
│                   ├── footer.html
│                   ├── header.html
│                   └── index.html
├── pipeline/
│   ├── README.md
│   ├── k8s/
│   │   ├── ingress.yaml
│   │   ├── process-pubsub.yaml
│   │   ├── processor.yaml
│   │   ├── provider.yaml
│   │   ├── scorer.yaml
│   │   ├── space.yaml
│   │   ├── state.yaml
│   │   ├── tweeter-pubsub.yaml
│   │   ├── twitter.yaml
│   │   └── viewer.yaml
│   ├── sentiment-scorer/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── config/
│   │   │   └── secret.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tweet-processor/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── config/
│   │   │   ├── result-pubsub.yaml
│   │   │   └── source-pubsub.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tweet-provider/
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── config/
│   │   │   ├── pubsub.yaml
│   │   │   ├── secret.yaml
│   │   │   ├── state.yaml
│   │   │   └── twitter.yaml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── tweet-viewer/
│       ├── Dockerfile
│       ├── Makefile
│       ├── config/
│       │   └── source-pubsub.yaml
│       ├── go.mod
│       ├── go.sum
│       ├── main.go
│       ├── resource/
│       │   ├── static/
│       │   │   ├── css/
│       │   │   │   └── app.css
│       │   │   └── js/
│       │   │       └── app.js
│       │   └── template/
│       │       ├── footer.html
│       │       ├── header.html
│       │       └── index.html
│       └── tweet.json
├── setup/
│   ├── Makefile
│   ├── README.md
│   ├── aks/
│   │   ├── Makefile
│   │   └── README.md
│   ├── config/
│   │   ├── actor-dashboard.json
│   │   ├── fluentd-config.yaml
│   │   ├── fluentd.yaml
│   │   ├── ingress-annotations.yaml
│   │   ├── ingress-config.yaml
│   │   ├── ingress-template.yaml
│   │   ├── namespace-template.yml
│   │   ├── sidecar-dashboard.json
│   │   ├── system-services-dashboard.json
│   │   └── zipkin.yaml
│   ├── gke/
│   │   ├── Makefile
│   │   └── README.md
│   └── kubectl-install-dapr
└── state-change-handler/
    ├── Dockerfile
    ├── Makefile
    ├── README.md
    ├── config/
    │   ├── pubsub.yaml
    │   └── statechange.yaml
    ├── go.mod
    ├── go.sum
    └── main.go
Download .txt
SYMBOL INDEX (126 symbols across 26 files)

FILE: autoscaling-on-queue/producer/main.go
  constant chars (line 24) | chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  function main (line 41) | func main() {
  function monitor (line 92) | func monitor(resultCh <-chan bool, stopCh <-chan struct{}) {
  function publish (line 120) | func publish(index int, resultCh chan<- bool, stopCh <-chan struct{}) {
  function getEventData (line 141) | func getEventData(index int) []byte {
  function getData (line 159) | func getData(length int) string {
  type requestContent (line 168) | type requestContent struct
  function getEnvVar (line 175) | func getEnvVar(key, fallbackValue string) string {
  function getEnvIntOrFail (line 182) | func getEnvIntOrFail(key, fallbackValue string) int {
  function getEnvDurationOrFail (line 191) | func getEnvDurationOrFail(key, fallbackValue string) time.Duration {
  function getEnvBoolOrFail (line 200) | func getEnvBoolOrFail(key, fallbackValue string) bool {

FILE: autoscaling-on-queue/subscriber/main.go
  constant primeStateKey (line 21) | primeStateKey = "high-prime"
  function main (line 34) | func main() {
  function processRequest (line 111) | func processRequest(ctx context.Context, in interface{}) error {
  function getEnvVar (line 117) | func getEnvVar(key, fallbackValue string) string {

FILE: cron-binding/main.go
  function main (line 20) | func main() {
  function scheduleHandler (line 35) | func scheduleHandler(ctx context.Context, in *common.BindingEvent) (out ...
  function getEnvVar (line 43) | func getEnvVar(key, fallbackValue string) string {

FILE: dapr-aci/src/main.go
  constant addInvokeHandlerError (line 21) | addInvokeHandlerError = "error adding invocation handler"
  constant startingServiceError (line 22) | startingServiceError  = "error starting service"
  constant clientCreateError (line 23) | clientCreateError     = "error creating Dapr client"
  constant addSubscriptionError (line 24) | addSubscriptionError  = "error subscribing to a topic"
  constant addInvocationError (line 25) | addInvocationError    = "error creating invcation handler"
  constant methodName (line 26) | methodName            = "ping"
  function main (line 41) | func main() {
  function invokeHandler (line 69) | func invokeHandler(ctx context.Context, in *common.InvocationEvent) (out...
  function eventHandler (line 77) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 95) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/grpc-echo-service/main.go
  function main (line 18) | func main() {
  function echoHandler (line 35) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
  function getEnvVar (line 50) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/http-format-converter/main.go
  function main (line 32) | func main() {
  type SourceEvent (line 57) | type SourceEvent struct
  function eventHandler (line 64) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 114) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/queue-event-consumer/main.go
  function main (line 20) | func main() {
  function eventHandler (line 40) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 45) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/queue-event-producer/main.go
  function main (line 29) | func main() {
  function produce (line 69) | func produce(ctx context.Context, c dapr.Client, t *time.Ticker) error {
  type roomReading (line 85) | type roomReading struct
  function getRoomReading (line 92) | func getRoomReading() interface{} {
  function getEnvVar (line 103) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/queue-format-converter/main.go
  function main (line 33) | func main() {
  type SourceEvent (line 58) | type SourceEvent struct
  function eventHandler (line 65) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 105) | func getEnvVar(key, fallbackValue string) string {

FILE: fan-out/service-format-converter/main.go
  function main (line 33) | func main() {
  type SourceEvent (line 58) | type SourceEvent struct
  function eventHandler (line 65) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 112) | func getEnvVar(key, fallbackValue string) string {

FILE: grpc-echo-service/main.go
  function main (line 18) | func main() {
  function echoHandler (line 35) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
  function getEnvVar (line 50) | func getEnvVar(key, fallbackValue string) string {

FILE: grpc-event-subscriber/main.go
  function main (line 20) | func main() {
  function eventHandler (line 40) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 51) | func getEnvVar(key, fallbackValue string) string {

FILE: hardened/src/app1/main.go
  constant methodName (line 18) | methodName      = "ping"
  constant invocationError (line 19) | invocationError = "error invoking"
  function main (line 32) | func main() {
  function handler (line 51) | func handler(ctx context.Context, in *common.InvocationEvent) (out *comm...
  function getEnvVar (line 70) | func getEnvVar(key, fallbackValue string) string {

FILE: hardened/src/app2/main.go
  constant methodName (line 20) | methodName      = "counter"
  constant stateCounterKey (line 21) | stateCounterKey = "count"
  constant addInvokeHandlerError (line 23) | addInvokeHandlerError = "error adding invocation handler"
  constant startingServiceError (line 24) | startingServiceError  = "error starting service"
  constant clientCreateError (line 25) | clientCreateError     = "error creating Dapr client"
  constant publisingError (line 26) | publisingError        = "error publishing"
  constant getStateError (line 27) | getStateError         = "error getting state"
  constant saveStateError (line 28) | saveStateError        = "error saving state"
  constant intParsingError (line 29) | intParsingError       = "error parsing data"
  function main (line 44) | func main() {
  function handler (line 62) | func handler(ctx context.Context, in *common.InvocationEvent) (out *comm...
  function getEnvVar (line 117) | func getEnvVar(key, fallbackValue string) string {

FILE: hardened/src/app3/main.go
  constant eventDataParsingError (line 19) | eventDataParsingError = "error parsing event data"
  constant addSubscriptionError (line 20) | addSubscriptionError  = "error adding topic subscription"
  constant startingServiceError (line 21) | startingServiceError  = "error starting service"
  constant intParsingError (line 22) | intParsingError       = "error parsing data"
  function main (line 33) | func main() {
  function handler (line 51) | func handler(ctx context.Context, e *common.TopicEvent) (retry bool, err...
  function getEnvVar (line 71) | func getEnvVar(key, fallbackValue string) string {

FILE: http-echo-service/main.go
  function main (line 18) | func main() {
  function echoHandler (line 32) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
  function getEnvVar (line 47) | func getEnvVar(key, fallbackValue string) string {

FILE: http-event-subscriber/main.go
  function main (line 23) | func main() {
  function eventHandler (line 44) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 55) | func getEnvVar(key, fallbackValue string) string {

FILE: order-cancellation/src/fn/ReceiveEvent.cs
  class ReceiveTopicMessage (line 20) | public static class ReceiveTopicMessage
    method Run (line 25) | [FunctionName("ReceiveTopicMessage")]

FILE: order-cancellation/src/viewer/main.go
  function main (line 34) | func main() {
  function wsHandler (line 74) | func wsHandler(w http.ResponseWriter, r *http.Request) {
  function rootHandler (line 78) | func rootHandler(w http.ResponseWriter, r *http.Request) {
  function faviconHandler (line 97) | func faviconHandler(w http.ResponseWriter, r *http.Request) {
  function eventHandler (line 101) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 116) | func getEnvVar(key, fallbackValue string) string {

FILE: order-cancellation/src/viewer/resource/static/js/app.js
  function appendLog (line 12) | function appendLog(item) {

FILE: pipeline/sentiment-scorer/main.go
  constant languageDefault (line 21) | languageDefault = "en"
  constant secretStoreName (line 22) | secretStoreName = "pipeline-secrets"
  constant secretStoreKey (line 23) | secretStoreKey  = "Azure:CognitiveAPIKey"
  function main (line 36) | func main() {
  function sentimentHandler (line 54) | func sentimentHandler(ctx context.Context, in *common.InvocationEvent) (...
  type SentimentScore (line 80) | type SentimentScore struct
  function getSentiment (line 85) | func getSentiment(ctx context.Context, lang, text string) (out *Sentimen...
  function getEnvVar (line 170) | func getEnvVar(key, fallbackValue string) string {
  function getSecret (line 177) | func getSecret(store, key string) string {

FILE: pipeline/tweet-processor/main.go
  function main (line 32) | func main() {
  function topicDataToSentimentRequest (line 59) | func topicDataToSentimentRequest(b []byte) (s *SentimentRequest, err err...
  function getSentimentScore (line 77) | func getSentimentScore(ctx context.Context, req *SentimentRequest) (scor...
  function tweetHandler (line 98) | func tweetHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  type TweetText (line 136) | type TweetText struct
  type SentimentRequest (line 145) | type SentimentRequest struct
  type SentimentScore (line 151) | type SentimentScore struct
  function getEnvVar (line 156) | func getEnvVar(key, fallbackValue string) string {

FILE: pipeline/tweet-provider/main.go
  function main (line 28) | func main() {
  function tweetHandler (line 51) | func tweetHandler(ctx context.Context, in *common.BindingEvent) (out []b...
  function getEnvVar (line 71) | func getEnvVar(key, fallbackValue string) string {

FILE: pipeline/tweet-viewer/main.go
  function main (line 34) | func main() {
  function wsHandler (line 74) | func wsHandler(w http.ResponseWriter, r *http.Request) {
  function rootHandler (line 78) | func rootHandler(w http.ResponseWriter, r *http.Request) {
  function faviconHandler (line 97) | func faviconHandler(w http.ResponseWriter, r *http.Request) {
  function eventHandler (line 101) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
  function getEnvVar (line 110) | func getEnvVar(key, fallbackValue string) string {

FILE: pipeline/tweet-viewer/resource/static/js/app.js
  function appendLog (line 12) | function appendLog(item) {

FILE: state-change-handler/main.go
  function main (line 24) | func main() {
  function bindingHandler (line 51) | func bindingHandler(ctx context.Context, in *common.BindingEvent) (out [...
  function getEnvVar (line 62) | func getEnvVar(key, fallbackValue string) string {
Condensed preview — 291 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,223K chars).
[
  {
    "path": ".gitignore",
    "chars": 342,
    "preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# VS Code \nDebug\n\n# Test binary, built with `go tes"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2020 Mark Chmarny\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 3161,
    "preview": "# Dapr demos\n\nCollection of personal [Dapr](https://dapr.io) demos.\n\n> Note, some of these demos require latest version "
  },
  {
    "path": "apim-gateway/README.md",
    "chars": 26545,
    "preview": "# Dapr & Azure API Management Integration Demo\n\nDapr integration with [Azure API Management](https://azure.microsoft.com"
  },
  {
    "path": "apim-gateway/apim/api.yaml",
    "chars": 1112,
    "preview": "openapi: 3.0.1\ninfo:\n  title: dapr\n  version: '1.0'\nservers:\n  - url: http://dapr-apim-demo.azure-api.net\n  - url: https"
  },
  {
    "path": "apim-gateway/apim/policy-all.json",
    "chars": 336,
    "preview": "{\n    \"properties\": {\n      \"format\": \"xml\",\n      \"value\": \"<policies><inbound><rate-limit-by-key calls=\\\"120\\\" renewal"
  },
  {
    "path": "apim-gateway/apim/policy-echo.json",
    "chars": 288,
    "preview": "{\n    \"properties\": {\n      \"format\": \"xml\",\n      \"value\": \"<policies><inbound><base /><set-backend-service backend-id="
  },
  {
    "path": "apim-gateway/apim/policy-message.json",
    "chars": 417,
    "preview": "{\n    \"properties\": {\n      \"format\": \"xml\",\n      \"value\": \"<policies><inbound><base /><publish-to-dapr topic=\\\"@(&quot"
  },
  {
    "path": "apim-gateway/apim/policy-save.json",
    "chars": 693,
    "preview": "{\n    \"properties\": {\n      \"format\": \"xml\",\n      \"value\": \"<policies><inbound><base /><set-variable name=\\\"key\\\" value"
  },
  {
    "path": "apim-gateway/k8s/binding.yaml",
    "chars": 277,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: demo-binding\nspec:\n  type: bindings.redis\n  metadata:\n  -"
  },
  {
    "path": "apim-gateway/k8s/echo-service.yaml",
    "chars": 789,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: echo-service\n  labels:\n    app: echo-service\n    demo: dapr-apim\n"
  },
  {
    "path": "apim-gateway/k8s/event-subscriber.yaml",
    "chars": 837,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: event-subscriber\n  labels:\n    app: event-subscriber\n    demo: da"
  },
  {
    "path": "apim-gateway/k8s/gateway.yaml",
    "chars": 1728,
    "preview": "# NOTE: Before deploying to a production environment, please review the documentation -> https://aka.ms/self-hosted-gate"
  },
  {
    "path": "apim-gateway/k8s/pubsub.yaml",
    "chars": 320,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: demo-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "autoscaling-on-queue/README.md",
    "chars": 7660,
    "preview": "# Autoscaling Dapr service based on queue depth \n\nDapr, with its modular building-block approach, along with the 10+ dif"
  },
  {
    "path": "autoscaling-on-queue/deployment/kafka-client.yaml",
    "chars": 211,
    "preview": "apiVersion: v1\nkind: Pod\nmetadata:\n name: kafka-client\nspec:\n containers:\n  - name: kafka-client\n    image: confluentinc"
  },
  {
    "path": "autoscaling-on-queue/deployment/kafka-pubsub.yaml",
    "chars": 348,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: autoscaling-pubsub\nspec:\n  type: pubsub.kafka\n  metadata:"
  },
  {
    "path": "autoscaling-on-queue/deployment/keda-2.0.0-beta.yaml",
    "chars": 453032,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  labels:\n    app.kubernetes.io/name: keda\n    app.kubernetes.io/part-of: keda-"
  },
  {
    "path": "autoscaling-on-queue/deployment/producer.yaml",
    "chars": 991,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: autoscaling-producer\n  labels:\n    app: autoscaling-producer\nspec"
  },
  {
    "path": "autoscaling-on-queue/deployment/subscriber-scaler.yaml",
    "chars": 424,
    "preview": "apiVersion: keda.sh/v1alpha1\nkind: ScaledObject\nmetadata:\n  name: subscriber-scaler\nspec:\n  scaleTargetRef:\n    name: au"
  },
  {
    "path": "autoscaling-on-queue/deployment/subscriber.yaml",
    "chars": 843,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: autoscaling-subscriber\n  labels:\n    app: autoscaling-subscriber\n"
  },
  {
    "path": "autoscaling-on-queue/producer/Dockerfile",
    "chars": 281,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "autoscaling-on-queue/producer/Makefile",
    "chars": 1012,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=autoscaling-producer\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help"
  },
  {
    "path": "autoscaling-on-queue/producer/go.mod",
    "chars": 358,
    "preview": "module github.com/mchmarny/dapr-demos/autoscaling-on-queue/producer\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "autoscaling-on-queue/producer/go.sum",
    "chars": 10521,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "autoscaling-on-queue/producer/main.go",
    "chars": 4704,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strc"
  },
  {
    "path": "autoscaling-on-queue/subscriber/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "autoscaling-on-queue/subscriber/Makefile",
    "chars": 1980,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=autoscaling-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: he"
  },
  {
    "path": "autoscaling-on-queue/subscriber/go.mod",
    "chars": 359,
    "preview": "module github.com/mchmarny/dapr-demos/autoscaling-on-queue/subscriber\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11."
  },
  {
    "path": "autoscaling-on-queue/subscriber/go.sum",
    "chars": 10668,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "autoscaling-on-queue/subscriber/main.go",
    "chars": 2703,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github"
  },
  {
    "path": "component-api/README.md",
    "chars": 5216,
    "preview": "# Use of Dapr as a component API Server\n\nThis demo users Dapr instance with API token authentication to show the use of "
  },
  {
    "path": "component-api/config/email.yaml",
    "chars": 274,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: send-email\nspec:\n  type: bindings.twilio.sendgrid\n  metad"
  },
  {
    "path": "component-api/config/state.yaml",
    "chars": 295,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: note-store\nspec:\n  type: state.redis\n  metadata:\n  - name"
  },
  {
    "path": "component-api/config/twitter.yaml",
    "chars": 511,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: query-twitter\nspec:\n  type: bindings.twitter\n  metadata:\n"
  },
  {
    "path": "component-api/sample/email.json",
    "chars": 172,
    "preview": "{\n    \"operation\": \"create\",\n    \"metadata\": {\n        \"emailTo\": \"daprdemo@chmarny.com\",\n        \"subject\": \"Dapr Demo\""
  },
  {
    "path": "component-api/sample/twitter.json",
    "chars": 148,
    "preview": "{\n    \"operation\": \"get\",\n    \"metadata\": {\n        \"query\": \"dapr AND serverless\",\n        \"lang\": \"en\",\n        \"resul"
  },
  {
    "path": "cron-binding/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "cron-binding/Makefile",
    "chars": 1722,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=cron-binding-demo\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: help tidy build "
  },
  {
    "path": "cron-binding/README.md",
    "chars": 1727,
    "preview": "# cron-binding\n\n## Binding\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: run\nspec:\n  type: bin"
  },
  {
    "path": "cron-binding/config/cron.yaml",
    "chars": 148,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: run\nspec:\n  type: bindings.cron\n  metadata:\n  - name: sch"
  },
  {
    "path": "cron-binding/go.mod",
    "chars": 100,
    "preview": "module github.com/mchmarny/dapr-demos/cron-binding\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "cron-binding/go.sum",
    "chars": 9715,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "cron-binding/k8s/component.yaml",
    "chars": 181,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: schedule\nspec:\n  type: bindings.cron\n  metadata:\n  - name"
  },
  {
    "path": "cron-binding/k8s/deployment.yaml",
    "chars": 769,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: cron-binding-demo\n  labels:\n    app: cron-binding-demo\n    demo: "
  },
  {
    "path": "cron-binding/main.go",
    "chars": 1031,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd "
  },
  {
    "path": "dapr-aci/README.md",
    "chars": 4862,
    "preview": "# Dapr sidecar in ACI\n\nDemo of Dapr sidecar in Azure Container Instances (ACI)\n\n## Setup \n\nThis demo illustrates simple "
  },
  {
    "path": "dapr-aci/components/pubsub.yaml",
    "chars": 280,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: pubsub\nspec:\n  type: pubsub.azure.servicebus\n  metadata:\n"
  },
  {
    "path": "dapr-aci/components/state.yaml",
    "chars": 250,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: store\nspec:\n  type: state.azure.tablestorage\n  metadata:\n"
  },
  {
    "path": "dapr-aci/deployment/app.yaml",
    "chars": 1447,
    "preview": "apiVersion: 2018-06-01\nlocation: westus\nname: dapraci\nproperties:\n  containers:\n  - name: app\n    properties:\n      imag"
  },
  {
    "path": "dapr-aci/src/Dockerfile",
    "chars": 266,
    "preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "dapr-aci/src/Makefile",
    "chars": 1534,
    "preview": "IMAGE_NAME  ?=aci-app\nIMAGE_TAG   ?=v0.2.2\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID      ?=aci-app\nA"
  },
  {
    "path": "dapr-aci/src/go.mod",
    "chars": 378,
    "preview": "module github.com/mchmarny/dapr-demos/dapr-aci/src\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/pkg/e"
  },
  {
    "path": "dapr-aci/src/go.sum",
    "chars": 12040,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "dapr-aci/src/main.go",
    "chars": 2679,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\tdapr \"github.co"
  },
  {
    "path": "dapr-api-on-aci/README.md",
    "chars": 4048,
    "preview": "# Dapr API in ACI\n\n* Purpose-configured instance of Dapr deployed into Azure Container Instances (ACI) with API token au"
  },
  {
    "path": "dapr-api-on-aci/email.yaml",
    "chars": 269,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: email\nspec:\n  type: bindings.twilio.sendgrid\n  metadata:\n"
  },
  {
    "path": "daprized-ingress/README.md",
    "chars": 6191,
    "preview": "# Dapr API on Cluster Ingress Controller \n\nThis how to will walk through the process of configuring Dapr api on your clu"
  },
  {
    "path": "daprized-ingress/config/ingress-annotations.yaml",
    "chars": 269,
    "preview": "controller:\n  podAnnotations:\n    dapr.io/enabled: \"true\"\n    dapr.io/app-id: \"nginx-ingress\"\n    dapr.io/app-protocol: "
  },
  {
    "path": "daprized-ingress/config/ingress-config.yaml",
    "chars": 366,
    "preview": "---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n  name: ingress-config\nspec:\n  tracing:\n    samplingRate:"
  },
  {
    "path": "daprized-ingress/config/ingress.yaml",
    "chars": 372,
    "preview": "apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: ingress-rules\n  annotations:\n    kubernetes.io/ingress.cl"
  },
  {
    "path": "daprized-ingress/config/namespace.yml",
    "chars": 381,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: secret-reader\nrules:\n- apiGroups: [\"\"]\n  resources"
  },
  {
    "path": "fan-out/README.md",
    "chars": 6611,
    "preview": "# fan-out demo \n\n`Fan-out` is a messaging pattern where single message source is \"broadcasted\" to multiple targets. The "
  },
  {
    "path": "fan-out/grpc-echo-service/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/grpc-echo-service/Makefile",
    "chars": 1967,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=grpc-echo-service\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help\n\n."
  },
  {
    "path": "fan-out/grpc-echo-service/README.md",
    "chars": 1742,
    "preview": "# grpc-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
  },
  {
    "path": "fan-out/grpc-echo-service/deployment.yaml",
    "chars": 804,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-echo-service\n  labels:\n    app: grpc-echo-service\n    demo: "
  },
  {
    "path": "fan-out/grpc-echo-service/go.mod",
    "chars": 105,
    "preview": "module github.com/mchmarny/dapr-demos/grpc-echo-service\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "fan-out/grpc-echo-service/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/grpc-echo-service/main.go",
    "chars": 1204,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
  },
  {
    "path": "fan-out/http-format-converter/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/http-format-converter/Makefile",
    "chars": 1525,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=http-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT    =xml"
  },
  {
    "path": "fan-out/http-format-converter/config/source-pubsub.yaml",
    "chars": 206,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-source-pubsub\nspec:\n  type: pubsub.redis\n  metadat"
  },
  {
    "path": "fan-out/http-format-converter/config/target-binding.yaml",
    "chars": 222,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-http-target-post-binding\nspec:\n  type: bindings.ht"
  },
  {
    "path": "fan-out/http-format-converter/go.mod",
    "chars": 152,
    "preview": "module github.com/mchmarny/dapr-demos/fan-out/http-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "fan-out/http-format-converter/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/http-format-converter/k8s/components.yaml",
    "chars": 343,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: grpc-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "fan-out/http-format-converter/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "fan-out/http-format-converter/main.go",
    "chars": 2919,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
  },
  {
    "path": "fan-out/queue-event-consumer/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/queue-event-consumer/Makefile",
    "chars": 1465,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=queue-format-consumer\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT    =xml"
  },
  {
    "path": "fan-out/queue-event-consumer/config/source-pabusb.yaml",
    "chars": 206,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-source-pubsub\nspec:\n  type: pubsub.redis\n  metadat"
  },
  {
    "path": "fan-out/queue-event-consumer/go.mod",
    "chars": 117,
    "preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-format-consumer\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "fan-out/queue-event-consumer/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/queue-event-consumer/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "fan-out/queue-event-consumer/k8s/target-kafka.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-event-consumer/k8s/target-redis.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-event-consumer/main.go",
    "chars": 1191,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
  },
  {
    "path": "fan-out/queue-event-producer/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/queue-event-producer/Makefile",
    "chars": 1471,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=queue-event-producer\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help"
  },
  {
    "path": "fan-out/queue-event-producer/config/target-pabusb.yaml",
    "chars": 206,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-source-pubsub\nspec:\n  type: pubsub.redis\n  metadat"
  },
  {
    "path": "fan-out/queue-event-producer/go.mod",
    "chars": 182,
    "preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-event-producer\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n\t"
  },
  {
    "path": "fan-out/queue-event-producer/go.sum",
    "chars": 10190,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/queue-event-producer/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "fan-out/queue-event-producer/k8s/target-kafka.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-event-producer/k8s/target-redis.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-event-producer/main.go",
    "chars": 2373,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github.com/dapr/"
  },
  {
    "path": "fan-out/queue-format-converter/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/queue-format-converter/Makefile",
    "chars": 1532,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=queue-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT    =xm"
  },
  {
    "path": "fan-out/queue-format-converter/config/kafka.yaml",
    "chars": 331,
    "preview": "version: '2'\nservices:\n  zookeeper:\n    image: wurstmeister/zookeeper:latest\n    ports:\n      - \"2181:2181\"\n  kafka:\n   "
  },
  {
    "path": "fan-out/queue-format-converter/config/source-pabusb.yaml",
    "chars": 206,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-source-pubsub\nspec:\n  type: pubsub.redis\n  metadat"
  },
  {
    "path": "fan-out/queue-format-converter/config/target-pubsub.yaml",
    "chars": 218,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-target-pubsub\nspec:\n  type: pubsub.kafka\n  metadat"
  },
  {
    "path": "fan-out/queue-format-converter/go.mod",
    "chars": 153,
    "preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0"
  },
  {
    "path": "fan-out/queue-format-converter/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/queue-format-converter/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "fan-out/queue-format-converter/k8s/target-kafka.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-format-converter/k8s/target-redis.yaml",
    "chars": 247,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-queue-kafka-target\nspec:\n  type: pubsub.kafka\n  me"
  },
  {
    "path": "fan-out/queue-format-converter/main.go",
    "chars": 2789,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
  },
  {
    "path": "fan-out/service-format-converter/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "fan-out/service-format-converter/Makefile",
    "chars": 1660,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=service-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT    ="
  },
  {
    "path": "fan-out/service-format-converter/config/source-pubsub.yaml",
    "chars": 206,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: fanout-source-pubsub\nspec:\n  type: pubsub.redis\n  metadat"
  },
  {
    "path": "fan-out/service-format-converter/go.mod",
    "chars": 155,
    "preview": "module github.com/mchmarny/dapr-demos/fan-out/service-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11"
  },
  {
    "path": "fan-out/service-format-converter/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "fan-out/service-format-converter/k8s/components.yaml",
    "chars": 343,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: grpc-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "fan-out/service-format-converter/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "fan-out/service-format-converter/main.go",
    "chars": 2943,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
  },
  {
    "path": "grpc-echo-service/Dockerfile",
    "chars": 266,
    "preview": "FROM golang:1.15.5 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "grpc-echo-service/Makefile",
    "chars": 1792,
    "preview": "RELEASE_VERSION  =v1.0.1\nSERVICE_NAME    ?=echo\nIMAGE_NAME      ?=grpc-echo-service\nIMAGE_TAG       ?=v0.1.4\nIMAGE_OWNER"
  },
  {
    "path": "grpc-echo-service/README.md",
    "chars": 2303,
    "preview": "# grpc-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
  },
  {
    "path": "grpc-echo-service/deployment/app.yaml",
    "chars": 742,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: echo-service\n  namespace: echo\n  labels:\n    app: echo-service\nsp"
  },
  {
    "path": "grpc-echo-service/deployment/space.yaml",
    "chars": 892,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  name: echo\n---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n  n"
  },
  {
    "path": "grpc-echo-service/go.mod",
    "chars": 254,
    "preview": "module github.com/mchmarny/dapr-demos/grpc-echo-service\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v1.0.0-rc-1\n\tgolang."
  },
  {
    "path": "grpc-echo-service/go.sum",
    "chars": 11542,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "grpc-echo-service/main.go",
    "chars": 1204,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
  },
  {
    "path": "grpc-event-subscriber/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "grpc-event-subscriber/Makefile",
    "chars": 3005,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=grpc-event-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: tidy test de"
  },
  {
    "path": "grpc-event-subscriber/README.md",
    "chars": 2121,
    "preview": "# grpc-event-subscriber\n\n## Components\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: events\nsp"
  },
  {
    "path": "grpc-event-subscriber/config/pubsub.yaml",
    "chars": 197,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: grpc-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "grpc-event-subscriber/go.mod",
    "chars": 109,
    "preview": "module github.com/mchmarny/dapr-demos/grpc-event-subscriber\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "grpc-event-subscriber/go.sum",
    "chars": 10027,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "grpc-event-subscriber/k8s/component.yaml",
    "chars": 367,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: grpc-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "grpc-event-subscriber/k8s/deployment.yaml",
    "chars": 909,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grpc-event-subscriber\n  labels:\n    app: grpc-event-subscriber\n  "
  },
  {
    "path": "grpc-event-subscriber/main.go",
    "chars": 1247,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
  },
  {
    "path": "hardened/Makefile",
    "chars": 1379,
    "preview": ".PHONY: all\nall: help\n\n.PHONY: apply\napply: ## Applies all and restarts the apps \n\t# apply\n\tkubectl apply -f k8s/ -n har"
  },
  {
    "path": "hardened/README.md",
    "chars": 14048,
    "preview": "# Hardening Dapr app demo \n\nIn addition to support for Kubernetes namespace isolation and Role-Based Access Control (RBA"
  },
  {
    "path": "hardened/config/pubsub.yaml",
    "chars": 346,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: pubsub\n  namespace: hardened\nspec:\n  type: pubsub.redis\n "
  },
  {
    "path": "hardened/config/state.yaml",
    "chars": 227,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: state\n  namespace: hardened\nspec:\n  type: state.redis\n  m"
  },
  {
    "path": "hardened/deployment/hardened/app1.yaml",
    "chars": 1329,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app1\n  namespace: hardened\n  labels:\n    app: app1\n    demo: hard"
  },
  {
    "path": "hardened/deployment/hardened/app2.yaml",
    "chars": 1393,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app2\n  namespace: hardened\n  labels:\n    app: app2\n    demo: hard"
  },
  {
    "path": "hardened/deployment/hardened/app3.yaml",
    "chars": 1074,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app3\n  namespace: hardened\n  labels:\n    app: app3\n    demo: hard"
  },
  {
    "path": "hardened/deployment/hardened/pubsub.yaml",
    "chars": 422,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: pubsub\n  namespace: hardened\nspec:\n  type: pubsub.redis\n "
  },
  {
    "path": "hardened/deployment/hardened/state.yaml",
    "chars": 303,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: state\n  namespace: hardened\nspec:\n  type: state.redis\n  m"
  },
  {
    "path": "hardened/deployment/namespace/ns.yaml",
    "chars": 57,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  name: hardened"
  },
  {
    "path": "hardened/deployment/namespace/role.yaml",
    "chars": 425,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: secret-reader\n  namespace: hardened\nrules:\n- apiGr"
  },
  {
    "path": "hardened/deployment/namespace/trace.yaml",
    "chars": 275,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: zipkin\n  namespace: hardened\nspec:\n  type: exporters.zipk"
  },
  {
    "path": "hardened/deployment/simple/app1.yaml",
    "chars": 760,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app1\n  namespace: hardened\n  labels:\n    app: app1\n    demo: hard"
  },
  {
    "path": "hardened/deployment/simple/app2.yaml",
    "chars": 813,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app2\n  namespace: hardened\n  labels:\n    app: app2\n    demo: hard"
  },
  {
    "path": "hardened/deployment/simple/app3.yaml",
    "chars": 760,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: app3\n  namespace: hardened\n  labels:\n    app: app3\n    demo: hard"
  },
  {
    "path": "hardened/deployment/simple/pubsub.yaml",
    "chars": 290,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: pubsub\n  namespace: hardened\nspec:\n  type: pubsub.redis\n "
  },
  {
    "path": "hardened/deployment/simple/state.yaml",
    "chars": 303,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: state\n  namespace: hardened\nspec:\n  type: state.redis\n  m"
  },
  {
    "path": "hardened/src/app1/Dockerfile",
    "chars": 266,
    "preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "hardened/src/app1/Makefile",
    "chars": 1145,
    "preview": "IMAGE_NAME  ?=hardened-app1\nIMAGE_TAG   ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID      ?=app"
  },
  {
    "path": "hardened/src/app1/go.mod",
    "chars": 140,
    "preview": "module github.com/mchmarny/dapr-demos/hardened/src/app1\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
  },
  {
    "path": "hardened/src/app1/go.sum",
    "chars": 11246,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "hardened/src/app1/main.go",
    "chars": 2052,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github.com/dapr/go-sdk/client\"\n\t\"github"
  },
  {
    "path": "hardened/src/app2/Dockerfile",
    "chars": 266,
    "preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "hardened/src/app2/Makefile",
    "chars": 1133,
    "preview": "IMAGE_NAME  ?=hardened-app2\nIMAGE_TAG   ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID      ?=app"
  },
  {
    "path": "hardened/src/app2/go.mod",
    "chars": 140,
    "preview": "module github.com/mchmarny/dapr-demos/hardened/src/app2\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
  },
  {
    "path": "hardened/src/app2/go.sum",
    "chars": 11246,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "hardened/src/app2/main.go",
    "chars": 3292,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\tdapr \"github.com/dapr/go-sdk/"
  },
  {
    "path": "hardened/src/app3/Dockerfile",
    "chars": 266,
    "preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "hardened/src/app3/Makefile",
    "chars": 1133,
    "preview": "IMAGE_NAME  ?=hardened-app3\nIMAGE_TAG   ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID      ?=app"
  },
  {
    "path": "hardened/src/app3/go.mod",
    "chars": 140,
    "preview": "module github.com/mchmarny/dapr-demos/hardened/src/app3\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
  },
  {
    "path": "hardened/src/app3/go.sum",
    "chars": 11246,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "hardened/src/app3/main.go",
    "chars": 1708,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/servi"
  },
  {
    "path": "http-echo-service/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "http-echo-service/Makefile",
    "chars": 1966,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=http-echo-service\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help\n\n."
  },
  {
    "path": "http-echo-service/README.md",
    "chars": 1741,
    "preview": "# http-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
  },
  {
    "path": "http-echo-service/deployment.yaml",
    "chars": 801,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: http-echo-service\n  labels:\n    app: http-echo-service\n    demo: "
  },
  {
    "path": "http-echo-service/go.mod",
    "chars": 105,
    "preview": "module github.com/mchmarny/dapr-demos/http-echo-service\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "http-echo-service/go.sum",
    "chars": 9638,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "http-echo-service/main.go",
    "chars": 1126,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
  },
  {
    "path": "http-event-subscriber/Dockerfile",
    "chars": 278,
    "preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
  },
  {
    "path": "http-event-subscriber/Makefile",
    "chars": 3224,
    "preview": "RELEASE_VERSION  =v0.11.1\nSERVICE_NAME    ?=http-event-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: tidy test de"
  },
  {
    "path": "http-event-subscriber/README.md",
    "chars": 2101,
    "preview": "# dapr-event-subscriber-template\n\n## Components\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: "
  },
  {
    "path": "http-event-subscriber/clooudevent.json",
    "chars": 417,
    "preview": "{\n    \"specversion\" : \"1.0\",\n    \"type\" : \"some.other.operation\",\n    \"source\" : \"https://domain.com/cloudevents/operati"
  },
  {
    "path": "http-event-subscriber/config/pubsub.yaml",
    "chars": 198,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: http-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "http-event-subscriber/go.mod",
    "chars": 109,
    "preview": "module github.com/mchmarny/dapr-demos/http-event-subscriber\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
  },
  {
    "path": "http-event-subscriber/go.sum",
    "chars": 9638,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "http-event-subscriber/k8s/component.yaml",
    "chars": 367,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: http-events\nspec:\n  type: pubsub.redis\n  metadata:\n  - na"
  },
  {
    "path": "http-event-subscriber/k8s/deployment.yaml",
    "chars": 919,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: http-event-subscriber\n  labels:\n    app: http-event-subscriber\n  "
  },
  {
    "path": "http-event-subscriber/main.go",
    "chars": 1316,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n"
  },
  {
    "path": "order-cancellation/README.md",
    "chars": 2944,
    "preview": "# Dapr integrations demo\n\n> WIP: This demo is being currently updated to Dapr v1.0.0.rc-1\n\n## Use-case\n\nOrder cancellati"
  },
  {
    "path": "order-cancellation/demo/Makefile",
    "chars": 1330,
    "preview": ".PHONY: help, workflowport, fnport, postmeta, postmail, postcancel, postgateway\nall: help\n\nworkflowport: ## Forwards Dap"
  },
  {
    "path": "order-cancellation/demo/README.md",
    "chars": 2726,
    "preview": "# Dapr integrations demo setup\n\n> Note, this setup assumes Kubernetes cluster created using the [demo cluster setup inst"
  },
  {
    "path": "order-cancellation/demo/component/audit-store.yaml",
    "chars": 440,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: order-audit-store\n  namespace: order\nspec:\n  type: state."
  },
  {
    "path": "order-cancellation/demo/component/email.yaml",
    "chars": 284,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: order-email\n  namespace: order\nspec:\n  type: bindings.twi"
  },
  {
    "path": "order-cancellation/demo/component/queue.yaml",
    "chars": 343,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: order-queue\n  namespace: order\nspec:\n  type: pubsub.redis"
  },
  {
    "path": "order-cancellation/demo/component/workflow-store.yaml",
    "chars": 432,
    "preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n  name: order-store\n  namespace: order\nspec:\n  type: state.mongod"
  },
  {
    "path": "order-cancellation/demo/config/order-cancel.json",
    "chars": 3916,
    "preview": "{\n    \"definition\": {\n        \"$schema\": \"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-"
  },
  {
    "path": "order-cancellation/demo/data/cancellation.json",
    "chars": 665,
    "preview": "{\n  \"id\": \"f727735e-b64e-11ea-b3de-0242ac130004\",\n  \"note\": \"Customer made a mistake\",\n  \"submitted_on\": \"2020-06-24T13:"
  },
  {
    "path": "order-cancellation/demo/data/email.json",
    "chars": 345,
    "preview": "{\n  \"operation\": \"create\",\n  \"metadata\": {\n    \"emailTo\": \"mchmarny@microsoft.com\",\n    \"subject\": \"Order cancellation c"
  },
  {
    "path": "order-cancellation/demo/data/meta.json",
    "chars": 129,
    "preview": "{\n  \"id\": \"b76b547e-b64e-11ea-b3de-0242ac130004\",\n  \"note\": \"Customer made a mistake\",\n  \"submitted_on\": \"2020-06-24T13:"
  },
  {
    "path": "order-cancellation/demo/deployment/auditor.yaml",
    "chars": 873,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: order-auditor\n  namespace: order\n  labels:\n    app: order-auditor"
  },
  {
    "path": "order-cancellation/demo/deployment/ingress.yaml",
    "chars": 471,
    "preview": "apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: order-ingress-rules\n  namespace: order\n  annotations:\n   "
  },
  {
    "path": "order-cancellation/demo/deployment/space.yaml",
    "chars": 898,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  name: order\n---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n  "
  },
  {
    "path": "order-cancellation/demo/deployment/viewer.yaml",
    "chars": 1029,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: order-viewer\n  namespace: order\n  labels:\n    app: order-viewer\ns"
  },
  {
    "path": "order-cancellation/demo/deployment/workflow.yaml",
    "chars": 1280,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: workflows-host\n  namespace: order\n  labels:\n    app: workflows-ho"
  },
  {
    "path": "order-cancellation/src/fn/.gitignore",
    "chars": 96,
    "preview": "# Build generated files in src\n/objd/**/*\n/obj/**/*\n/bin/**/*\n/gen/**/*\n/.vs/**/*\n/.vscode/**/*\n"
  },
  {
    "path": "order-cancellation/src/fn/DaprAzFn.csproj",
    "chars": 882,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.0</TargetFramework>\n    <AzureFunc"
  }
]

// ... and 91 more files (download for full content)

About this extraction

This page contains the full source code of the mchmarny/dapr-demos GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 291 files (1.1 MB), approximately 318.3k tokens, and a symbol index with 126 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!