├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 1_Event_type_request.yml │ ├── 2_feature_request.yml │ ├── 3_bug-report.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── kubevalidator.yaml ├── renovate.json ├── semantic.yml └── workflows │ ├── ci.yml │ ├── push-experimental-image.yml │ └── push-stable-image.yml ├── .gitignore ├── Contributing.md ├── LICENSE ├── README.md ├── charts └── k8s-event-grid-bridge │ ├── .helmignore │ ├── Chart.yaml │ ├── LICENSE │ ├── README.md │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── secret.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ │ └── test-connection.yaml │ └── values.yaml ├── docs ├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _includes │ └── footer_custom.html ├── _sass │ └── color_schemes │ │ └── custom.scss ├── chart-registry │ ├── artifacthub-repo.yml │ ├── index.yaml │ ├── k8s-event-grid-bridge-0.1.0.tgz │ └── k8s-event-grid-bridge-0.2.0.tgz ├── client-libraries.md ├── client-libraries │ └── dotnet.md ├── concept.md ├── deploy.md ├── deploy │ └── helm.md ├── favicon.ico ├── index.md ├── media │ ├── concept │ │ ├── detailed-overview.png │ │ ├── end-to-end.png │ │ └── high-level-overview.png │ ├── logo-with-name-small.png │ ├── logo-with-name.png │ ├── logo-with-name.svg │ ├── logo.png │ ├── logo.svg │ └── walkthroughs │ │ ├── delivered-events.png │ │ ├── received-event-details.png │ │ ├── received-events.png │ │ └── using-kubernetes-event-grid-bridge-with-opsgenie-kubernetes-event-exporter.png ├── supported-events.md ├── supported-events │ ├── Raw.md │ ├── cluster-autoscaler │ │ ├── index.md │ │ └── node-group-scale-out.md │ └── deployments │ │ ├── index.md │ │ ├── scale-in.md │ │ └── scale-out.md ├── walkthroughs.md └── walkthroughs │ └── kubernetes-event-exporter.md ├── events ├── KEDA │ ├── KEDAScaleTargetActivated.json │ ├── KEDAScaleTargetDeactivated.json │ ├── KEDAScalerFailed.json │ ├── KEDAScalersStarted.json │ └── ScaledObjectReady.json ├── cluster-autoscaler │ ├── NotTriggerScaleUp.json │ ├── ScaleDown.json │ ├── ScaleDownEmpty.json │ ├── ScaledUpGroup.json │ └── TriggeredScaleUp.json └── core │ ├── ContainerStarted.json │ ├── FailedCreatePodSandBox.json │ ├── ImagePulled.json │ ├── InvalidDiskCapacity.json │ ├── KillingContainer.json │ ├── KillingPod.json │ ├── NodeAllocatableEnforced.json │ ├── NodeHasNoDiskPressure.json │ ├── NodeHasSufficientMemory.json │ ├── NodeHasSufficientPID.json │ ├── NodeReady.json │ ├── PodScheduled.json │ ├── PodUnhealthyDueToHealthProbe.json │ ├── PodUnhealthyDueToReadinessProbe.json │ ├── PodVolumeMountFailed.json │ ├── PullingImage.json │ ├── RegisteredNode.json │ ├── RemovingNode.json │ ├── ScalingReplicaSetDown.json │ ├── ScalingReplicaSetUp.json │ ├── StartingKubelet.json │ ├── SuccesfulCreate.json │ ├── SuccessfulDelete.json │ └── UpdatedLoadBalancer.json ├── examples └── helm-chart.config.yaml ├── kubernetes-event-exporter-config.yml ├── media └── schematics.pptx ├── netlify.toml └── src ├── .dockerignore ├── Kubernetes.EventGrid.Bridge.Contracts ├── Enums │ ├── HorizontalScaleDirection.cs │ └── KubernetesEventType.cs ├── Events │ ├── ClusterAutoscaler │ │ ├── ClusterAutoscalerScaleEventPayload.cs │ │ ├── NewNodeGroupSizeInfo.cs │ │ └── NodeGroupResizeInfo.cs │ └── Deployments │ │ ├── DeploymentScaleEventPayload.cs │ │ └── ReplicaInfo.cs ├── Extensions │ └── EnumExtensions.cs ├── Kubernetes.EventGrid.Bridge.Contracts.csproj ├── LICENSE └── logo.png ├── Kubernetes.EventGrid.Bridge.Host ├── .dockerignore ├── .gitignore ├── Dockerfile ├── Kubernetes.EventGrid.Bridge.Host.csproj ├── KubernetesEventExporterFunction.cs ├── Properties │ ├── serviceDependencies.json │ └── serviceDependencies.local.json ├── Startup.cs └── host.json ├── Kubernetes.EventGrid.Bridge.sln ├── Kubernetes.EventGrid.Bridge.sln.DotSettings ├── Kubernetes.EventGrid.Core ├── CloudEvents │ ├── CloudEventFactory.cs │ └── Interfaces │ │ └── ICloudEventFactory.cs ├── Kubernetes.EventGrid.Core.csproj └── Kubernetes │ ├── Converters │ ├── ClusterAutoscalerEventConverter.cs │ ├── DeploymentControllerEventConverter.cs │ ├── EventConverter.cs │ └── IEventConverter.cs │ ├── Events │ ├── Interfaces │ │ └── IKubernetesEvent.cs │ └── KubernetesEvent.cs │ ├── Interfaces │ ├── IKubernetesClusterInfoProvider.cs │ └── IKubernetesEventParser.cs │ ├── KubernetesClusterInfoProvider.cs │ ├── KubernetesEventContext.cs │ ├── KubernetesEventParser.cs │ └── Parsers │ ├── ClusterAutoscalerEventParser.cs │ └── DeploymentControllerEventParser.cs └── Kubernetes.EventGrid.Tests.Unit ├── CloudEvents └── CloudEventFactoryUnitTests.cs ├── Events └── KubernetesEventSamples.cs ├── Extensions ├── EnumExtensionsUnitTests.cs └── Enums │ └── ExampleEnum.cs ├── Kubernetes.EventGrid.Tests.Unit.csproj ├── Kubernetes ├── ClusterAutoscaler │ └── ClusterAutoscalerEventParserUnitTests.cs ├── Deployments │ ├── DeploymentControllerEventParserUnitTests.cs │ ├── DeploymentControllerEventParsingTests.cs │ └── KubernetesEventParserUnitTestsForDeployments.cs ├── KubernetesClusterInfoProviderUnitTests.cs └── KubernetesEventParserUnitTests.cs └── UnitTest.cs /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # General owners 2 | * @tomkerkhove -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [tomkerkhove] -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_Event_type_request.yml: -------------------------------------------------------------------------------- 1 | name: Event type request ⚡ 2 | description: Suggest a new event type that would be an added value 3 | labels: "event-type,feature-request" 4 | assignees: tomkerkhove 5 | body: 6 | - type: input 7 | attributes: 8 | label: Contact Details 9 | description: How can we get in touch with you if we need more info? 10 | placeholder: ex. email@example.com 11 | validations: 12 | required: false 13 | - type: textarea 14 | attributes: 15 | label: Scenario 16 | description: "What scenario will this new event type support?" 17 | placeholder: "A clear and concise description of the scenario where this type would be used." 18 | - type: input 19 | attributes: 20 | label: Proposed Event Type 21 | description: "What event type would you propose?" 22 | placeholder: "A proposal for the event type, for example `Kubernetes.ClusterAutoscaler.Scale.Out`." 23 | validations: 24 | required: false 25 | - type: textarea 26 | attributes: 27 | label: Proposed Event Payload 28 | description: What event payload would you propose? 29 | placeholder: "A proposal for the event payload that you would like to have." 30 | value: | 31 | ```json 32 | { 33 | "key": "value" 34 | } 35 | ``` 36 | validations: 37 | required: false 38 | - type: textarea 39 | attributes: 40 | label: Raw Kubernetes Event 41 | description: What is the raw Kubernetes event that we should convert for this event? 42 | placeholder: "A raw Kubernetes event payload that is the source." 43 | value: | 44 | ```json 45 | { 46 | "key": "value" 47 | } 48 | ``` 49 | validations: 50 | required: false 51 | - type: dropdown 52 | attributes: 53 | label: Source Component 54 | description: What component is emitting the original raw event? 55 | options: 56 | - Kubernetes Control Plane 57 | - Cluster Autoscaler 58 | - Other 59 | validations: 60 | required: false 61 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 🧭 2 | description: Suggest an idea for this project 3 | labels: "feature-request" 4 | assignees: tomkerkhove 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Proposal 9 | description: "What would you like to have as a feature" 10 | placeholder: "A clear and concise description of what you want to happen." 11 | - type: input 12 | attributes: 13 | label: Contact Details 14 | description: How can we get in touch with you if we need more info? 15 | placeholder: ex. email@example.com 16 | validations: 17 | required: false 18 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Report a bug 🐛 2 | description: Create a report to help us improve 3 | labels: "bug" 4 | assignees: tomkerkhove 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Report 9 | description: "What bug have you encountered?" 10 | placeholder: "A clear and concise description of what the bug is." 11 | - type: input 12 | attributes: 13 | label: Contact Details 14 | description: How can we get in touch with you if we need more info? 15 | placeholder: ex. email@example.com 16 | validations: 17 | required: false 18 | - type: textarea 19 | attributes: 20 | label: Expected Behavior 21 | description: What did you expect to happen? 22 | placeholder: What did you expect to happen? 23 | validations: 24 | required: true 25 | - type: textarea 26 | attributes: 27 | label: Actual Behavior 28 | description: Also tell us, what did you see is happen? 29 | placeholder: Tell us what you see that is happening 30 | validations: 31 | required: true 32 | - type: textarea 33 | attributes: 34 | label: Steps to Reproduce the Problem 35 | description: "How can we reproduce this bug? Please walk us through it step by step." 36 | value: | 37 | 1. 38 | 2. 39 | 3. 40 | ... 41 | validations: 42 | required: true 43 | - type: dropdown 44 | attributes: 45 | label: Version 46 | description: What version of our software are you running? 47 | options: 48 | - 0.1.0 49 | - experimental 50 | validations: 51 | required: false 52 | - type: dropdown 53 | attributes: 54 | label: Platform 55 | description: Where is your cluster running? 56 | options: 57 | - Microsoft Azure 58 | - Amazon Web Services 59 | - Google Cloud 60 | - Alibaba Cloud 61 | - Other 62 | validations: 63 | required: false 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question 💬 4 | url: https://github.com/tomkerkhove/k8s-event-grid-bridge/discussions/new 5 | about: Ask a question or request support for using Kubernetes Event Grid Bridge. 6 | - name: Sponsor 💘 7 | url: https://github.com/sponsors/tomkerkhove 8 | about: Sponsor Tom to keep on maintaining Kubernetes Event Grid Bridge. 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | Fixes # -------------------------------------------------------------------------------- /.github/kubevalidator.yaml: -------------------------------------------------------------------------------- 1 | apiversion: v1alpha 2 | kind: KubeValidatorConfig 3 | spec: 4 | manifests: 5 | - glob: deploy/*.yaml 6 | schemas: 7 | - version: 1.10.0 8 | - version: 1.11.0 9 | - version: 1.12.0 10 | - version: 1.13.0 11 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "branchPrefix": "renovate-", 3 | "separateMajorMinor": false, 4 | "labels": [ 5 | "dependencies" 6 | ], 7 | "assignees": [ 8 | "@tomkerkhove" 9 | ], 10 | "ignoreDeps": [], 11 | "prHourlyLimit": 0, 12 | "prConcurrentLimit": 0, 13 | "extends": [ 14 | "config:base", 15 | "default:pinDigestsDisabled", 16 | "default:disablePrControls" 17 | ], 18 | "nuget": { 19 | "enabled": true 20 | }, 21 | "vulnerabilityAlerts": { 22 | "labels": [ 23 | "security" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Semantic Pull Requests PR validation, see https://github.com/zeke/semantic-pull-requests#configuration for full reference 2 | # Always validate the PR title, and ignore the commits 3 | titleOnly: true 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | paths: 5 | - '.github/workflows/ci.yml' 6 | - 'charts/**' 7 | - 'src/**' 8 | 9 | env: 10 | CHART_NAME: k8s-event-grid-bridge 11 | IMAGE_NAME: ghcr.io/tomkerkhove/k8s-event-grid-bridge 12 | IMAGE_TAG: experimental 13 | 14 | jobs: 15 | solution: 16 | name: Runtime (Solution) 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Build Solution 21 | run: dotnet build ./src/Kubernetes.EventGrid.Bridge.sln --configuration Release 22 | - name: Run Unit Tests 23 | run: dotnet test ./src/Kubernetes.EventGrid.Tests.Unit/Kubernetes.EventGrid.Tests.Unit.csproj --filter Category=Unit 24 | 25 | runtime: 26 | name: Runtime (Docker) 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v3 30 | - name: Build the Docker image 31 | run: docker build ./src/ --file ./src/Kubernetes.EventGrid.Bridge.Host/Dockerfile --tag ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 32 | 33 | lint-helm-3-x: 34 | name: Lint Helm Chart 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: Check out code 38 | uses: actions/checkout@v3 39 | 40 | - name: Helm install 41 | uses: Azure/setup-helm@v3 42 | 43 | - name: Lint Helm chart 44 | run: helm lint ./charts/${{ env.CHART_NAME }} --values examples/helm-chart.config.yaml 45 | 46 | deploy-helm-3-x: 47 | name: Deploy Chart to Kind Cluster 48 | needs: [lint-helm-3-x] 49 | runs-on: ubuntu-latest 50 | env: 51 | KUBERNETES_NAMESPACE: k8s-event-grid-bridge 52 | steps: 53 | - name: Check out code 54 | uses: actions/checkout@v3 55 | 56 | - name: Helm install 57 | uses: Azure/setup-helm@v3 58 | 59 | - name: Create k8s Kind Cluster 60 | uses: helm/kind-action@v1.3.0 61 | 62 | - name: Show Kubernetes version 63 | run: | 64 | kubectl version 65 | - name: Show Helm version 66 | run: | 67 | helm version 68 | - name: Create namespace 69 | run: kubectl create ns ${{ env.KUBERNETES_NAMESPACE }} 70 | 71 | - name: Change Kubernetes context to use namespace 72 | run: kubectl config set-context --current --namespace=${{ env.KUBERNETES_NAMESPACE }} 73 | 74 | - name: Template Helm chart 75 | run: helm template ${{ env.CHART_NAME }} ./charts/${{ env.CHART_NAME }}/ --values examples/helm-chart.config.yaml 76 | 77 | - name: Install Helm chart 78 | run: helm install ${{ env.CHART_NAME }} ./charts/${{ env.CHART_NAME }}/ --values examples/helm-chart.config.yaml --wait 79 | 80 | - name: Show installed Helm charts 81 | run: helm ls 82 | if: always() 83 | 84 | - name: Show Kubernetes resources 85 | run: kubectl get all 86 | if: always() 87 | -------------------------------------------------------------------------------- /.github/workflows/push-experimental-image.yml: -------------------------------------------------------------------------------- 1 | name: Push Experimental Docker Image 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'src/**' 7 | branches: 8 | - main 9 | env: 10 | IMAGE_NAME: ghcr.io/tomkerkhove/k8s-event-grid-bridge 11 | IMAGE_TAG: experimental 12 | NUGET_PACKAGE_VERSION: 0.3.0 13 | 14 | jobs: 15 | push_docker_to_ghcr: 16 | name: Push Docker image to GitHub Container Registry 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Docker Login 21 | uses: docker/login-action@v2.0.0 22 | with: 23 | registry: ghcr.io 24 | username: tomkerkhove 25 | password: ${{ secrets.CONTAINER_REGISTRY_KEY }} 26 | - name: Build the Docker image 27 | run: docker build ./src/ --file ./src/Kubernetes.EventGrid.Bridge.Host/Dockerfile --tag ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 28 | - name: Push the Docker image 29 | run: docker push ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 30 | push_nuget_to_ghpr: 31 | name: Push NuGet package to GitHub Package Registry 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Set version suffix for main branch 36 | uses: allenevans/set-env@v2.2.0 37 | with: 38 | VERSION_SUFFIX: ${{ github.sha }} 39 | # Set NuGet package name since env.NUGET_PACKAGE_NAME doesn't resolve the variables 40 | - name: Set NuGet package name 41 | uses: allenevans/set-env@v2.2.0 42 | with: 43 | NUGET_PACKAGE_NAME: Kubernetes.EventGrid.Bridge.Contracts.${{ env.NUGET_PACKAGE_VERSION }}-$VERSION_SUFFIX.nupkg 44 | # Set NuGet package name since env.NUGET_PACKAGE_PATH doesn't resolve the variables 45 | - name: Set NuGet package path 46 | uses: allenevans/set-env@v2.2.0 47 | with: 48 | NUGET_PACKAGE_PATH: ./src/Kubernetes.EventGrid.Bridge.Contracts/bin/Release/${{ env.NUGET_PACKAGE_NAME }} 49 | - name: Build Solution 50 | run: dotnet build ./src/Kubernetes.EventGrid.Bridge.sln --configuration Release -p:Version=${{ env.NUGET_PACKAGE_VERSION }}-$VERSION_SUFFIX 51 | - name: Run Unit Tests 52 | run: dotnet test ./src/Kubernetes.EventGrid.Tests.Unit/Kubernetes.EventGrid.Tests.Unit.csproj --filter Category=Unit 53 | - name: Push NuGet package 54 | run: dotnet nuget push "${{ env.NUGET_PACKAGE_PATH }}" --api-key ${{ secrets.NUGET_REGISTRY_GHPR_PAT }} --source "https://nuget.pkg.github.com/tomkerkhove/index.json" 55 | - name: Upload NuGet Package 56 | uses: actions/upload-artifact@v3 57 | with: 58 | name: ${{ env.NUGET_PACKAGE_NAME }} 59 | path: ${{ env.NUGET_PACKAGE_PATH }} 60 | -------------------------------------------------------------------------------- /.github/workflows/push-stable-image.yml: -------------------------------------------------------------------------------- 1 | name: Push Stable Docker Image 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: 'Version' 7 | required: true 8 | default: '0.2.0-rc.1' 9 | release: 10 | types: [published] 11 | env: 12 | IMAGE_NAME: ghcr.io/tomkerkhove/k8s-event-grid-bridge 13 | IMAGE_TAG: "${{ github.event.release.tag_name }}" 14 | jobs: 15 | verify: 16 | name: Verify App 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Run Unit Tests 21 | run: dotnet test ./src/Kubernetes.EventGrid.Tests.Unit/Kubernetes.EventGrid.Tests.Unit.csproj --filter Category=Unit 22 | push_docker_to_ghcr: 23 | name: Push Docker image to GitHub Container Registry 24 | runs-on: ubuntu-latest 25 | needs: [verify] 26 | steps: 27 | - uses: actions/checkout@v3 28 | - name: Docker Login 29 | uses: docker/login-action@v2.0.0 30 | with: 31 | registry: ghcr.io 32 | username: tomkerkhove 33 | password: ${{ secrets.CONTAINER_REGISTRY_KEY }} 34 | - name: Build the Docker image 35 | run: docker build ./src/ --file ./src/Kubernetes.EventGrid.Bridge.Host/Dockerfile --tag ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 36 | - name: Push the Docker image 37 | run: docker push ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 38 | push_nuget_to_ghpr: 39 | name: Push NuGet package to NuGet.org 40 | runs-on: ubuntu-latest 41 | needs: [verify] 42 | steps: 43 | - uses: actions/checkout@v3 44 | - name: Set version for release trigger 45 | uses: allenevans/set-env@v2.2.0 46 | if: ${{ github.event_name == 'release' }} 47 | with: 48 | NUGET_VERSION: ${{ github.event.release.tag_name }} 49 | - name: Set version for workflow dispatch 50 | uses: allenevans/set-env@v2.2.0 51 | if: ${{ github.event_name == 'workflow_dispatch' }} 52 | with: 53 | NUGET_VERSION: ${{ github.event.inputs.version }} 54 | # Set NuGet package name since env.NUGET_PACKAGE_NAME doesn't resolve the variables 55 | - name: Set NuGet package name 56 | uses: allenevans/set-env@v2.2.0 57 | with: 58 | NUGET_PACKAGE_NAME: Kubernetes.EventGrid.Bridge.Contracts.${{ env.NUGET_VERSION }}.nupkg 59 | # Set NuGet package name since env.NUGET_PACKAGE_PATH doesn't resolve the variables 60 | - name: Set NuGet package path 61 | uses: allenevans/set-env@v2.2.0 62 | with: 63 | NUGET_PACKAGE_PATH: ./src/Kubernetes.EventGrid.Bridge.Contracts/bin/Release/${{ env.NUGET_PACKAGE_NAME }} 64 | - name: Build Solution 65 | run: dotnet build ./src/Kubernetes.EventGrid.Bridge.sln --configuration Release -p:Version=${{ env.NUGET_VERSION }} 66 | - name: Push NuGet package 67 | run: dotnet nuget push "${{ env.NUGET_PACKAGE_PATH }}" --api-key ${{ secrets.NUGET_REGISTRY_NUGETORG_APIKEY }} --source https://api.nuget.org/v3/index.json 68 | - name: Upload NuGet Package 69 | uses: actions/upload-artifact@v3 70 | with: 71 | name: ${{ env.NUGET_PACKAGE_NAME }} 72 | path: ${{ env.NUGET_PACKAGE_PATH }} 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | examples/helm-chart.config.local.yaml 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local Jekyll output 334 | _site/* 335 | docs/_site/* 336 | !.azure-devops/*/release/ -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | Contributing to Kubernetes Event Grid Bridge 2 | === 3 | 4 | Thanks for helping making Kubernetes Event Grid Bridge better! 5 | 6 | ## Shipping a new version 7 | 8 | You can easily release a new Helm chart version: 9 | 10 | 1. Update the version of the Helm chart in `Chart.yaml` 11 | 2. Package the Helm chart 12 | ```shell 13 | $ helm package .\charts\k8s-event-grid-bridge\ 14 | Successfully packaged chart and saved it to: C:\Code\GitHub\k8s-event-grid-bridge\k8s-event-grid-bridge-0.1.0.tgz 15 | ``` 16 | 17 | 3. Move the new chart to the docs folder 18 | ```shell 19 | $ mv k8s-event-grid-bridge-*.tgz .\docs\chart-registry\ 20 | ``` 21 | 22 | 4. Re-index the Helm repo to add our new version 23 | ```shell 24 | $ helm repo index .\docs\chart-registry\ --url https://k8s-event-grid-bridge.tomkerkhove.be/chart-registry 25 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tom Kerkhove 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![Logo](./docs/media/logo-with-name.png) 4 | [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/k8s-event-grid-bridge)](https://artifacthub.io/packages/search?repo=k8s-event-grid-bridge) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftomkerkhove%2Fk8s-event-grid-bridge.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftomkerkhove%2Fk8s-event-grid-bridge?ref=badge_shield) 5 | 6 | 7 | --- 8 | 9 | :loudspeaker: **Tom is not actively maintaining Kubernetes Event Grid Bridge but happy to have somebody help.** 10 | 11 | --- 12 | 13 | A simple event bridge for Kubernetes native events forwarding [CloudEvents v1.0](https://cloudevents.io/) compliant events to Azure Event Grid into Microsoft Azure. 14 | 15 | The bridge is not in charge of acquiring the events from Kubernetes, but you can use tools such as [Opsgenie's Kubernetes Event Exporter](https://github.com/opsgenie/kubernetes-event-exporter) and forward them to the bridge. 16 | 17 | # Documentation 18 | 19 | Learn more about Kubernetes Event Grid Bridge on [docs.k8s-event-grid-bridge.io](https://docs.k8s-event-grid-bridge.io/) such as : 20 | 21 | - Supported events 22 | - Deployment 23 | - ... 24 | 25 | ## License 26 | 27 | This is licensed under The MIT License (MIT). Which means that you can use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the web application. But you always need to state that Tom Kerkhove is the original author of this web application. 28 | 29 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftomkerkhove%2Fk8s-event-grid-bridge.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftomkerkhove%2Fk8s-event-grid-bridge?ref=badge_large) 30 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: k8s-event-grid-bridge 3 | description: A simple event bridge for Kubernetes native events to Azure Event Grid. 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.2.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | appVersion: 0.2.0 24 | home: http://k8s-event-grid-bridge.tomkerkhove.be/ 25 | icon: https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/main/docs/media/logo.png 26 | keywords: 27 | - kubernetes 28 | - kubernetes events 29 | - azure 30 | - azure event grid 31 | - event 32 | - events 33 | - event exporting 34 | - event driven 35 | - cloudevents 36 | sources: 37 | - https://github.com/tomkerkhove/k8s-event-grid-bridge 38 | maintainers: 39 | - name: Tom Kerkhove 40 | url: https://github.com/tomkerkhove 41 | annotations: 42 | artifacthub.io/changes: | 43 | - https://github.com/tomkerkhove/k8s-event-grid-bridge/releases/tag/0.2.0 44 | artifacthub.io/containsSecurityUpdates: "false" 45 | artifacthub.io/images: | 46 | - name: k8s-event-grid-bridge 47 | image: ghcr.io/tomkerkhove/k8s-event-grid-bridge:experimental -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tom Kerkhove 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/README.md: -------------------------------------------------------------------------------- 1 | ![Logo](https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/main/docs/media/logo-with-name-small.png) 2 | 3 | A simple event bridge for Kubernetes native events forwarding [CloudEvents v1.0](https://cloudevents.io/) compliant events to Azure Event Grid into Microsoft Azure. 4 | 5 | The bridge is not in charge of acquiring the events from Kubernetes, but you can use tools such as [Opsgenie's Kubernetes Event Exporter](https://github.com/opsgenie/kubernetes-event-exporter) and forward them to the bridge. 6 | 7 | [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/k8s-event-grid-bridge)](https://artifacthub.io/packages/search?repo=k8s-event-grid-bridge) 8 | 9 | ## Configuration 10 | 11 | The following table lists the configurable parameters of the Helm chart and 12 | their default values. 13 | 14 | | Parameter | Description | Default | 15 | | :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | 16 | | `azure.eventGrid.key` | Authentication key for Azure Event Grid. | `` | 17 | | `azure.eventGrid.topicUri` | Uri of the Azure Event Grid topic to send events to. | `` | 18 | | `kubernetes.cluster.name` | Name of the Kubernetes cluster. This will be used in the emitted events and observability to support multi-cluster events into a single Azure Event Grid topic. | `unknown-cluster` | 19 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Kubernetes Event Grid Bridge is up & running! 2 | 3 | Internal workloads can forward requests to http://{{ include "k8s-event-grid-bridge.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}. 4 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "k8s-event-grid-bridge.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "k8s-event-grid-bridge.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "k8s-event-grid-bridge.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "k8s-event-grid-bridge.labels" -}} 37 | helm.sh/chart: {{ include "k8s-event-grid-bridge.chart" . }} 38 | {{ include "k8s-event-grid-bridge.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "k8s-event-grid-bridge.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "k8s-event-grid-bridge.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "k8s-event-grid-bridge.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "k8s-event-grid-bridge.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "k8s-event-grid-bridge.fullname" . }} 5 | labels: 6 | {{- include "k8s-event-grid-bridge.labels" . | nindent 4 }} 7 | spec: 8 | replicas: {{ .Values.replicaCount }} 9 | strategy: 10 | type: RollingUpdate 11 | rollingUpdate: 12 | maxSurge: 1 13 | maxUnavailable: 1 14 | selector: 15 | matchLabels: 16 | {{- include "k8s-event-grid-bridge.selectorLabels" . | nindent 6 }} 17 | template: 18 | metadata: 19 | {{- with .Values.podAnnotations }} 20 | annotations: 21 | {{- toYaml . | nindent 8 }} 22 | {{- end }} 23 | labels: 24 | {{- include "k8s-event-grid-bridge.selectorLabels" . | nindent 8 }} 25 | spec: 26 | {{- with .Values.imagePullSecrets }} 27 | imagePullSecrets: 28 | {{- toYaml . | nindent 8 }} 29 | {{- end }} 30 | serviceAccountName: {{ include "k8s-event-grid-bridge.serviceAccountName" . }} 31 | securityContext: 32 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 33 | containers: 34 | - name: {{ .Chart.Name }} 35 | securityContext: 36 | {{- toYaml .Values.securityContext | nindent 12 }} 37 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 38 | imagePullPolicy: {{ .Values.image.pullPolicy }} 39 | ports: 40 | - name: http 41 | containerPort: 80 42 | protocol: TCP 43 | env: 44 | - name: FUNCTIONS_WORKER_RUNTIME 45 | value: dotnet 46 | - name: AzureWebJobsStorage 47 | valueFrom: 48 | secretKeyRef: 49 | name: {{ include "k8s-event-grid-bridge.fullname" . }} 50 | key: AzureWebJobsStorage 51 | - name: EventGridBridge_Kubernetes_Cluster_Name 52 | value: {{ .Values.kubernetes.cluster.name | quote }} 53 | - name: EventGridBridge_EventGrid_Topic_Uri 54 | value: {{ .Values.azure.eventGrid.topicUri }} 55 | - name: EventGridBridge_EventGrid_Topic_Key 56 | valueFrom: 57 | secretKeyRef: 58 | name: {{ include "k8s-event-grid-bridge.fullname" . }} 59 | key: EventGridAuthenticationKey 60 | resources: 61 | {{- toYaml .Values.resources | nindent 12 }} 62 | {{- with .Values.nodeSelector }} 63 | nodeSelector: 64 | {{- toYaml . | nindent 8 }} 65 | {{- end }} 66 | {{- with .Values.affinity }} 67 | affinity: 68 | {{- toYaml . | nindent 8 }} 69 | {{- end }} 70 | {{- with .Values.tolerations }} 71 | tolerations: 72 | {{- toYaml . | nindent 8 }} 73 | {{- end }} 74 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ include "k8s-event-grid-bridge.fullname" . }} 5 | labels: 6 | {{- include "k8s-event-grid-bridge.labels" . | nindent 4 }} 7 | data: 8 | AzureWebJobsStorage: {{ .Values.azure.storage.connectionString | b64enc | quote }} 9 | EventGridAuthenticationKey: {{ .Values.azure.eventGrid.key | b64enc | quote }} -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "k8s-event-grid-bridge.fullname" . }} 5 | labels: 6 | {{- include "k8s-event-grid-bridge.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "k8s-event-grid-bridge.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "k8s-event-grid-bridge.serviceAccountName" . }} 6 | labels: 7 | {{- include "k8s-event-grid-bridge.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "k8s-event-grid-bridge.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "k8s-event-grid-bridge.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test-success 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "k8s-event-grid-bridge.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /charts/k8s-event-grid-bridge/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for k8s-event-grid-bridge. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: containers.k8s-event-grid-bridge.io/tomkerkhove/k8s-event-grid-bridge 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | azure: 18 | storage: 19 | connectionString: 20 | eventGrid: 21 | topicUri: 22 | key: 23 | 24 | kubernetes: 25 | cluster: 26 | name: "unknown-cluster" 27 | 28 | service: 29 | type: ClusterIP 30 | port: 8888 31 | 32 | serviceAccount: 33 | # Specifies whether a service account should be created 34 | create: true 35 | # Annotations to add to the service account 36 | annotations: {} 37 | # The name of the service account to use. 38 | # If not set and create is true, a name is generated using the fullname template 39 | name: "" 40 | 41 | podAnnotations: {} 42 | 43 | podSecurityContext: {} 44 | # fsGroup: 2000 45 | 46 | securityContext: {} 47 | # capabilities: 48 | # drop: 49 | # - ALL 50 | # readOnlyRootFilesystem: true 51 | # runAsNonRoot: true 52 | # runAsUser: 1000 53 | 54 | resources: {} 55 | # We usually recommend not to specify default resources and to leave this as a conscious 56 | # choice for the user. This also increases chances charts run on environments with little 57 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 58 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 59 | # limits: 60 | # cpu: 100m 61 | # memory: 128Mi 62 | # requests: 63 | # cpu: 100m 64 | # memory: 128Mi 65 | 66 | nodeSelector: {} 67 | 68 | tolerations: [] 69 | 70 | affinity: {} 71 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found 🕵️‍♂️

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | gem "jekyll", "~> 4.2.0" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | gem "minima", "~> 2.5", ">= 2.5.1" 13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 14 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 15 | # gem "github-pages", group: :jekyll_plugins 16 | # If you have any plugins, put them here! 17 | group :jekyll_plugins do 18 | gem "jekyll-feed", "~> 0.15", ">= 0.15.1" 19 | end 20 | 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 22 | # and associated library. 23 | platforms :mingw, :x64_mingw, :mswin, :jruby do 24 | gem "tzinfo", "~> 2.0" 25 | gem "tzinfo-data" 26 | end 27 | 28 | # Performance-booster for watching directories on Windows 29 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 30 | 31 | gem "just-the-docs", ">= 0.3.3" 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.0) 5 | public_suffix (>= 2.0.2, < 5.0) 6 | colorator (1.1.0) 7 | concurrent-ruby (1.1.9) 8 | em-websocket (0.5.2) 9 | eventmachine (>= 0.12.9) 10 | http_parser.rb (~> 0.6.0) 11 | eventmachine (1.2.7) 12 | eventmachine (1.2.7-x64-mingw32) 13 | ffi (1.15.3) 14 | ffi (1.15.3-x64-mingw32) 15 | forwardable-extended (2.6.0) 16 | http_parser.rb (0.6.0) 17 | i18n (1.8.10) 18 | concurrent-ruby (~> 1.0) 19 | jekyll (4.2.0) 20 | addressable (~> 2.4) 21 | colorator (~> 1.0) 22 | em-websocket (~> 0.5) 23 | i18n (~> 1.0) 24 | jekyll-sass-converter (~> 2.0) 25 | jekyll-watch (~> 2.0) 26 | kramdown (~> 2.3) 27 | kramdown-parser-gfm (~> 1.0) 28 | liquid (~> 4.0) 29 | mercenary (~> 0.4.0) 30 | pathutil (~> 0.9) 31 | rouge (~> 3.0) 32 | safe_yaml (~> 1.0) 33 | terminal-table (~> 2.0) 34 | jekyll-feed (0.15.1) 35 | jekyll (>= 3.7, < 5.0) 36 | jekyll-sass-converter (2.1.0) 37 | sassc (> 2.0.1, < 3.0) 38 | jekyll-seo-tag (2.7.1) 39 | jekyll (>= 3.8, < 5.0) 40 | jekyll-watch (2.2.1) 41 | listen (~> 3.0) 42 | just-the-docs (0.3.3) 43 | jekyll (>= 3.8.5) 44 | jekyll-seo-tag (~> 2.0) 45 | rake (>= 12.3.1, < 13.1.0) 46 | kramdown (2.3.1) 47 | rexml 48 | kramdown-parser-gfm (1.1.0) 49 | kramdown (~> 2.0) 50 | liquid (4.0.3) 51 | listen (3.5.1) 52 | rb-fsevent (~> 0.10, >= 0.10.3) 53 | rb-inotify (~> 0.9, >= 0.9.10) 54 | mercenary (0.4.0) 55 | minima (2.5.1) 56 | jekyll (>= 3.5, < 5.0) 57 | jekyll-feed (~> 0.9) 58 | jekyll-seo-tag (~> 2.1) 59 | pathutil (0.16.2) 60 | forwardable-extended (~> 2.6) 61 | public_suffix (4.0.6) 62 | rake (13.0.4) 63 | rb-fsevent (0.11.0) 64 | rb-inotify (0.10.1) 65 | ffi (~> 1.0) 66 | rexml (3.2.5) 67 | rouge (3.26.0) 68 | safe_yaml (1.0.5) 69 | sassc (2.4.0) 70 | ffi (~> 1.9) 71 | sassc (2.4.0-x64-mingw32) 72 | ffi (~> 1.9) 73 | terminal-table (2.0.0) 74 | unicode-display_width (~> 1.1, >= 1.1.1) 75 | tzinfo (2.0.4) 76 | concurrent-ruby (~> 1.0) 77 | tzinfo-data (1.2020.6) 78 | tzinfo (>= 1.0.0) 79 | unicode-display_width (1.7.0) 80 | wdm (0.1.1) 81 | 82 | PLATFORMS 83 | ruby 84 | x64-mingw32 85 | 86 | DEPENDENCIES 87 | jekyll (~> 4.2.0) 88 | jekyll-feed (~> 0.15, >= 0.15.1) 89 | just-the-docs (>= 0.3.3) 90 | minima (~> 2.5, >= 2.5.1) 91 | tzinfo (~> 2.0) 92 | tzinfo-data 93 | wdm (~> 0.1.1) 94 | 95 | BUNDLED WITH 96 | 2.1.4 97 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | # 11 | # If you need help with YAML syntax, here are some quick references for you: 12 | # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml 13 | # https://learnxinyminutes.com/docs/yaml/ 14 | # 15 | # Site settings 16 | # These are used to personalize your new site. If you look in the HTML files, 17 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 18 | # You can create any custom variable you would like, and they will be accessible 19 | # in the templates via {{ site.myvariable }}. 20 | 21 | title: Kubernetes Event Grid Bridge 22 | email: kerkhove.tom@gmail.com 23 | description: >- # this means to ignore newlines until "baseurl:" 24 | A simple event bridge for Kubernetes native events forwarding CloudEvents v1.0 compliant events to Azure Event Grid into Microsoft Azure. 25 | 26 | The bridge is not in charge of acquiring the events from Kubernetes, but you can use tools such as Opsgenie's Kubernetes Event Exporter and forward them to the bridge. 27 | baseurl: "" # the subpath of your site, e.g. /blog 28 | url: "https://docs.k8s-event-grid-bridge.io" # the base hostname & protocol for your site, e.g. http://example.com 29 | twitter_username: tomkerkhove 30 | github_username: tomkerkhove 31 | 32 | # Build settings 33 | theme: just-the-docs 34 | plugins: 35 | - jekyll-feed 36 | 37 | # Theme settings 38 | # All settings can be found on https://pmarsceill.github.io/just-the-docs/docs/configuration/ 39 | # color_scheme: dark 40 | color_scheme: custom 41 | 42 | # Footer last edited timestamp 43 | last_edit_timestamp: true 44 | 45 | # Footer "Edit this page on GitHub" link text 46 | gh_edit_link: true # show or hide edit this page link 47 | gh_edit_link_text: "Edit this page on GitHub." 48 | gh_edit_repository: "https://github.com/tomkerkhove/k8s-event-grid-bridge" # the github URL for your repo 49 | gh_edit_branch: "main" # the branch that your docs is served from 50 | gh_edit_source: docs # the source that your files originate from 51 | gh_edit_view_mode: "tree" 52 | 53 | # Links 54 | aux_links: 55 | "GitHub": 56 | - "https://github.com/tomkerkhove/k8s-event-grid-bridge" 57 | "License": 58 | - "https://github.com/tomkerkhove/k8s-event-grid-bridge/blob/main/LICENSE" 59 | 60 | # Exclude from processing. 61 | # The following items will not be processed, by default. 62 | # Any item listed under the `exclude:` key here will be automatically added to 63 | # the internal "default list". 64 | # 65 | # Excluded items can be processed by explicitly listing the directories or 66 | # their entries' file path in the `include:` list. 67 | # 68 | # exclude: 69 | # - .sass-cache/ 70 | # - .jekyll-cache/ 71 | # - gemfiles/ 72 | # - Gemfile 73 | # - Gemfile.lock 74 | # - node_modules/ 75 | # - vendor/bundle/ 76 | # - vendor/cache/ 77 | # - vendor/gems/ 78 | # - vendor/ruby/ 79 | -------------------------------------------------------------------------------- /docs/_includes/footer_custom.html: -------------------------------------------------------------------------------- 1 | 2 | Copyright © 2021 Tom Kerkhove distributed by an MIT license. 3 | -------------------------------------------------------------------------------- /docs/_sass/color_schemes/custom.scss: -------------------------------------------------------------------------------- 1 | $link-color: $blue-000; 2 | $btn-primary-color: $blue-100; -------------------------------------------------------------------------------- /docs/chart-registry/artifacthub-repo.yml: -------------------------------------------------------------------------------- 1 | # Artifact Hub repository metadata file 2 | repositoryID: 8941e9b1-8478-4921-92ed-de5548857727 3 | owners: 4 | - name: kerkhove.tom 5 | email: kerkhove.tom@gmail.com 6 | -------------------------------------------------------------------------------- /docs/chart-registry/index.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | entries: 3 | k8s-event-grid-bridge: 4 | - annotations: 5 | artifacthub.io/changes: | 6 | - https://github.com/tomkerkhove/k8s-event-grid-bridge/releases/tag/0.2.0 7 | artifacthub.io/containsSecurityUpdates: "false" 8 | artifacthub.io/images: |- 9 | - name: k8s-event-grid-bridge 10 | image: ghcr.io/tomkerkhove/k8s-event-grid-bridge:experimental 11 | apiVersion: v2 12 | appVersion: 0.2.0 13 | created: "2021-04-19T10:34:15.5081668+02:00" 14 | description: A simple event bridge for Kubernetes native events to Azure Event 15 | Grid. 16 | digest: 3b1fb88a4c82049566a0730a7e1f5d62b13433a7fde7ddd565f445012c79b36d 17 | home: http://k8s-event-grid-bridge.tomkerkhove.be/ 18 | icon: https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/main/docs/media/logo.png 19 | keywords: 20 | - kubernetes 21 | - kubernetes events 22 | - azure 23 | - azure event grid 24 | - event 25 | - events 26 | - event exporting 27 | - event driven 28 | - cloudevents 29 | maintainers: 30 | - name: Tom Kerkhove 31 | url: https://github.com/tomkerkhove 32 | name: k8s-event-grid-bridge 33 | sources: 34 | - https://github.com/tomkerkhove/k8s-event-grid-bridge 35 | type: application 36 | urls: 37 | - https://k8s-event-grid-bridge.tomkerkhove.be/chart-registry/k8s-event-grid-bridge-0.2.0.tgz 38 | version: 0.2.0 39 | - annotations: 40 | artifacthub.io/changes: | 41 | - Initial version 42 | artifacthub.io/containsSecurityUpdates: "false" 43 | artifacthub.io/images: |- 44 | - name: k8s-event-grid-bridge 45 | image: ghcr.io/tomkerkhove/k8s-event-grid-bridge:experimental 46 | apiVersion: v2 47 | appVersion: 0.1.0 48 | created: "2021-04-19T10:34:15.5041659+02:00" 49 | description: A simple event bridge for Kubernetes native events to Azure Event 50 | Grid. 51 | digest: 877275eed46b6fa576bc4137b001864abe48cd5834b78667c41fed8f34586bdc 52 | home: http://k8s-event-grid-bridge.tomkerkhove.be/ 53 | icon: https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/main/docs/media/logo.png 54 | keywords: 55 | - kubernetes 56 | - kubernetes events 57 | - azure 58 | - azure event grid 59 | - event 60 | - events 61 | - event exporting 62 | - event driven 63 | maintainers: 64 | - name: Tom Kerkhove 65 | url: https://github.com/tomkerkhove 66 | name: k8s-event-grid-bridge 67 | sources: 68 | - https://github.com/tomkerkhove/k8s-event-grid-bridge 69 | type: application 70 | urls: 71 | - https://k8s-event-grid-bridge.tomkerkhove.be/chart-registry/k8s-event-grid-bridge-0.1.0.tgz 72 | version: 0.1.0 73 | generated: "2021-04-19T10:34:15.4991661+02:00" 74 | -------------------------------------------------------------------------------- /docs/chart-registry/k8s-event-grid-bridge-0.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/chart-registry/k8s-event-grid-bridge-0.1.0.tgz -------------------------------------------------------------------------------- /docs/chart-registry/k8s-event-grid-bridge-0.2.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/chart-registry/k8s-event-grid-bridge-0.2.0.tgz -------------------------------------------------------------------------------- /docs/client-libraries.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Client Libraries 4 | permalink: /client-libraries/ 5 | has_children: true 6 | has_toc: true 7 | nav_order: 5 8 | --- 9 | 10 | Kubernetes Event Grid Bridge provides client libraries to simplify usage of the events that are emitted. -------------------------------------------------------------------------------- /docs/client-libraries/dotnet.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: .NET 4 | parent: Client Libraries 5 | --- 6 | 7 | # .NET 8 | 9 | [![Badge](https://badgen.net/nuget/v/Kubernetes.EventGrid.Bridge.Contracts)](https://www.nuget.org/packages/Kubernetes.EventGrid.Bridge.Contracts/) 10 | 11 | We provide a NuGet package that contains all supported contracts & event types: 12 | 13 | ```shell 14 | > PM > Install-Package Kubernetes.EventGrid.Bridge.Contracts 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/concept.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Concept 4 | permalink: /concept/ 5 | nav_order: 2 6 | --- 7 | 8 | Kubernetes provides a wide variety of events, giving insights on what is going on in your cluster. 9 | 10 | However; often you want to react to those events outside of your cluster and integrate with existing applications & SaaS services. 11 | 12 | With **Kubernetes Event Grid Bridge; you can easily forward & centralize all cluster events from various clusters into Azure Event Grid**, regardless of where your clusters are. 13 | 14 | **All forwarded events are [CloudEvents v1.0](https://cloudevents.io/) compliant**, allowing you to integrate with any tools from the ecosystem. 15 | 16 | ![High Level Overview](/media/concept/high-level-overview.png) 17 | 18 | By using Azure Event Grid, you providing a centralized eventing hub in your platform to which all parties can subscribe, filter and process events based on their needs; by only publishing them once. 19 | 20 | # How does it work? 21 | 22 | Kubernetes Event Grid Bridge is single-purpose tool that is only in charge of accepting & forwarding events to Microsoft Azure and only acts as a bridge. 23 | 24 | It does not automatically subscribe to cluster events but the Kubernetes community provides enough tools that can be used to trigger our bridge, such as Opsgenie's [Kubernetes Event Exporter](https://github.com/opsgenie/kubernetes-event-exporter). 25 | 26 | ![End-to-end](/media/concept/end-to-end.png) 27 | 28 | Kubernetes provides a range of events which all comply to a generic format which can make it harder to process. 29 | 30 | With **Kubernetes Event Grid Bridge, we are planning to provide consumer-friendly events** designed to solve user needs. 31 | 32 | This makes it easier to build workloads that extend Kubernetes. 33 | 34 | # Unleash the power of Kubernetes events 35 | 36 | By forwarding all events to Azure Event Grid, consumers can easily filter on various attributes such as event type, cluster name, namespace, payload and more. 37 | 38 | By doing this, consumers can focus on solving platform needs by only processing the information they need. 39 | 40 | Customers typically rely on these events to: 41 | 42 | - Create **scaling awareness** by automatically posting messages to team communication tools, such as Slack 43 | - **Automatically open support tickets** for failing pods 44 | - Measure & visualize custom metrics on your **(scaling) dashboard** 45 | - ... 46 | 47 |
48 | 49 | ![Detailed Overview](/media/concept/detailed-overview.png) 50 | -------------------------------------------------------------------------------- /docs/deploy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Deploy 4 | permalink: /deploy/ 5 | has_children: true 6 | has_toc: true 7 | nav_order: 4 8 | --- 9 | 10 | Here's an overview of the deployment options for running the Kubernetes Event Grid Bridge. -------------------------------------------------------------------------------- /docs/deploy/helm.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Helm 4 | parent: Deploy 5 | --- 6 | 7 | # Helm 8 | 9 | [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/k8s-event-grid-bridge)](https://artifacthub.io/packages/search?repo=k8s-event-grid-bridge) 10 | 11 | We allow you to easily deploy to Kubernetes through Helm. 12 | 13 | ## Adding our Helm chart registry 14 | 15 | - Install the `k8s-event-grid-bridge` Chart repository: 16 | 17 | ``` 18 | ❯ helm repo add k8s-event-grid-bridge https://k8s-event-grid-bridge.tomkerkhove.be/chart-registry 19 | "k8s-event-grid-bridge" has been added to your repositories 20 | ``` 21 | 22 | - Refresh your local chart repositories: 23 | 24 | ``` 25 | ❯ helm repo update 26 | Hang tight while we grab the latest from your chart repositories... 27 | ...Successfully got an update from the "k8s-event-grid-bridge" chart repository 28 | Update Complete. ⎈ Happy Helming!⎈ 29 | ``` 30 | 31 | - If all goes well you should be able to list all `k8s-event-grid-bridge` charts: 32 | 33 | ``` 34 | ❯ helm search hub k8s-event-grid-bridge 35 | URL CHART VERSION APP VERSION DESCRIPTION 36 | https://hub.helm.sh/charts/k8s-event-grid-bridg... 0.1.0 0.1.0 A simple event bridge for Kubernetes native eve... 37 | ``` 38 | 39 | ## Installing the chart 40 | 41 | You can easily install our Kubernetes Event Grid Bridge as following: 42 | 43 | ``` 44 | ❯ helm install k8s-event-grid-bridge \ 45 | k8s-event-grid-bridge/k8s-event-grid-bridge \ 46 | --set azure.storage.connectionString='' \ 47 | --set azure.eventGrid.topicUri='' \ 48 | --set azure.eventGrid.key='' 49 | ``` 50 | 51 | Our Helm chart provides a variety of configuration options which you can explore in our full [values file](https://github.com/tomkerkhove/k8s-event-grid-bridge/blob/main/charts/k8s-event-grid-bridge/values.yaml) to see all configurable values. 52 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # Feel free to add content and custom Front Matter to this file. 3 | # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults 4 | 5 | layout: home 6 | title: Welcome 7 | nav_order: 1 8 | --- 9 | 10 | ![Logo](./media/logo-with-name.png) 11 | 12 | [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/k8s-event-grid-bridge)](https://artifacthub.io/packages/search?repo=k8s-event-grid-bridge) 13 | 14 | A simple event bridge for Kubernetes native events forwarding [CloudEvents v1.0](https://cloudevents.io/) compliant events to Azure Event Grid into Microsoft Azure. 15 | 16 | ![High Level Overview](/media/concept/high-level-overview.png) 17 | 18 | The bridge is not in charge of acquiring the events from Kubernetes, but you can use tools such as [Opsgenie's Kubernetes Event Exporter](https://github.com/opsgenie/kubernetes-event-exporter) and forward them to the bridge. 19 | 20 | [GitHub](https://github.com/tomkerkhove/k8s-event-grid-bridge){: .btn } -------------------------------------------------------------------------------- /docs/media/concept/detailed-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/concept/detailed-overview.png -------------------------------------------------------------------------------- /docs/media/concept/end-to-end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/concept/end-to-end.png -------------------------------------------------------------------------------- /docs/media/concept/high-level-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/concept/high-level-overview.png -------------------------------------------------------------------------------- /docs/media/logo-with-name-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/logo-with-name-small.png -------------------------------------------------------------------------------- /docs/media/logo-with-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/logo-with-name.png -------------------------------------------------------------------------------- /docs/media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/logo.png -------------------------------------------------------------------------------- /docs/media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 49 | 50 | 52 | 57 | 58 | 67 | 71 | 77 | 79 | 85 | 91 | 97 | 103 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /docs/media/walkthroughs/delivered-events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/walkthroughs/delivered-events.png -------------------------------------------------------------------------------- /docs/media/walkthroughs/received-event-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/walkthroughs/received-event-details.png -------------------------------------------------------------------------------- /docs/media/walkthroughs/received-events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/walkthroughs/received-events.png -------------------------------------------------------------------------------- /docs/media/walkthroughs/using-kubernetes-event-grid-bridge-with-opsgenie-kubernetes-event-exporter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/docs/media/walkthroughs/using-kubernetes-event-grid-bridge-with-opsgenie-kubernetes-event-exporter.png -------------------------------------------------------------------------------- /docs/supported-events.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Supported Events 4 | permalink: /supported-events/ 5 | has_children: true 6 | has_toc: true 7 | nav_order: 3 8 | --- 9 | 10 | Kubernetes Event Grid Bridge is planning on providing a range of consumption-friendly events allowing you to extend Kubernetes. 11 | 12 | For now, we allow you to process raw Kubernetes event without any translation - Just like we got it from Kubernetes! 13 | 14 | Do you have event requests? [Let us know](https://github.com/tomkerkhove/k8s-event-grid-bridge/issues/new?assignees=&labels=event-type%2Cfeature-request&template=Event_type_request.md)! 15 | -------------------------------------------------------------------------------- /docs/supported-events/Raw.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Raw 4 | parent: Supported Events 5 | --- 6 | 7 | ## Raw 8 | 9 | ![Availability Badge](https://img.shields.io/badge/Available%20Starting-v0.1.0-green.svg) 10 | 11 | This event represents a raw Kubernetes event without translation. 12 | 13 | ### Event Type 14 | 15 | `Kubernetes.Events.Raw` 16 | 17 | ### Example 18 | 19 | ```json 20 | { 21 | "specversion": "1.0", 22 | "type": "Kubernetes.Events.Raw", 23 | "source": "http://kubernetes", 24 | "id": "727b39dd-7ac1-4783-94f1-4a1d5de3d1da", 25 | "time": "2021-01-10T09:22:09.6277244Z", 26 | "datacontenttype": "application/json", 27 | "data": { 28 | "metadata": { 29 | "name": "k8s-event-bridge-workload.1656cffa3223676d", 30 | "namespace": "monitoring", 31 | "selfLink": "/api/v1/namespaces/monitoring/events/k8s-event-bridge-workload.1656cffa3223676d", 32 | "uid": "f5b5c92f-86c3-454f-a269-287dc1c46e62", 33 | "resourceVersion": "68019", 34 | "creationTimestamp": "2021-01-03T19:36:30Z", 35 | "managedFields": [{ 36 | "manager": "kube-controller-manager", 37 | "operation": "Update", 38 | "apiVersion": "v1", 39 | "time": "2021-01-03T19:36:30Z" 40 | }] 41 | }, 42 | "reason": "ScalingReplicaSet", 43 | "message": "Scaled up replica set k8s-event-bridge-workload-76888d9cc9 to 1", 44 | "source": { 45 | "component": "deployment-controller" 46 | }, 47 | "firstTimestamp": "2021-01-03T19:36:30Z", 48 | "lastTimestamp": "2021-01-03T19:36:30Z", 49 | "count": 1, 50 | "type": "Normal", 51 | "reportingComponent": "", 52 | "reportingInstance": "", 53 | "involvedObject": { 54 | "kind": "Deployment", 55 | "namespace": "monitoring", 56 | "name": "k8s-event-bridge-workload", 57 | "uid": "4f3b68fc-126f-4df3-8961-c70d4d18f045", 58 | "apiVersion": "apps/v1", 59 | "resourceVersion": "68017", 60 | "labels": { 61 | "app": "k8s-event-bridge" 62 | } 63 | } 64 | } 65 | } 66 | ``` -------------------------------------------------------------------------------- /docs/supported-events/cluster-autoscaler/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Cluster Autoscaler 4 | parent: Supported Events 5 | has_children: true 6 | --- 7 | 8 | ## Cluster Autoscaler 9 | 10 | Provides various user-friendly events for [Kubernetes' Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler). 11 | -------------------------------------------------------------------------------- /docs/supported-events/cluster-autoscaler/node-group-scale-out.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Scale Out Node Group 4 | parent: Cluster Autoscaler 5 | grand_parent: Supported Events 6 | --- 7 | 8 | ## Scale Out Node Group (Cluster Autoscaler) 9 | 10 | ![Availability Badge](https://img.shields.io/badge/Available%20Starting-v0.2.0-green.svg) 11 | 12 | This event represents Cluster Autoscaler scaling out a node group in the cluster. 13 | 14 | Learn more about it in the [official `cluster-autoscaler` FAQ](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-events-are-emitted-by-ca). 15 | 16 | ### Event Type 17 | 18 | `Kubernetes.Autoscaling.ClusterAutoscaler.V1.NodeGroup.ScaleOut` 19 | 20 | ### Example 21 | 22 | ```json 23 | { 24 | "specversion": "1.0", 25 | "type": "Kubernetes.Autoscaling.ClusterAutoscaler.NodeGroup.ScaleOut", 26 | "source": "http://kubernetes/autoscaling/cluster-autoscaler", 27 | "id": "6833c9ff-567b-4b80-9cc5-ea34963097d4", 28 | "time": "2021-04-11T13:00:40.539442Z", 29 | "subject": "/local-cluster/node-groups/aks-agentpool-11593772-vmss", 30 | "datacontenttype": "application/json", 31 | "data": { 32 | "nodeGroup": { 33 | "name": "aks-agentpool-11593772-vmss", 34 | "sizeInfo": { 35 | "new": 16, 36 | "old": 15, 37 | "maximum": 20 38 | } 39 | } 40 | } 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/supported-events/deployments/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Deployments 4 | parent: Supported Events 5 | has_children: true 6 | --- 7 | 8 | ## Deployments 9 | 10 | Provides various user-friendly events for [Kubernetes Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/). 11 | -------------------------------------------------------------------------------- /docs/supported-events/deployments/scale-in.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Scale In 4 | parent: Deployments 5 | grand_parent: Supported Events 6 | --- 7 | 8 | ## Scale In (Deployment) 9 | 10 | ![Availability Badge](https://img.shields.io/badge/Available%20Starting-v0.2.0-green.svg) 11 | 12 | This event represents a Deployment that is scaling in. 13 | 14 | ### Event Type 15 | 16 | `Kubernetes.Autoscaling.Deployment.V1.ScaleIn` 17 | 18 | ### Example 19 | 20 | ```json 21 | { 22 | "specversion": "1.0", 23 | "type": "Kubernetes.Autoscaling.Deployment.V1.ScaleIn", 24 | "source": "http://kubernetes/core/controllers/deployment", 25 | "id": "5410aed4-a1a8-48a4-aab4-0417551cbbf9", 26 | "time": "2021-04-16T06:42:54.7839842Z", 27 | "subject": "/local-cluster/namespaces/monitoring/deployments/k8s-event-grid-bridge-workload", 28 | "datacontenttype": "application/json", 29 | "data": { 30 | "deployment": { 31 | "name": "k8s-event-grid-bridge-workload", 32 | "namespace": "monitoring", 33 | "labels": { 34 | "app": "k8s-event-grid-bridge" 35 | } 36 | }, 37 | "replicaSet": { 38 | "name": "k8s-event-grid-bridge-workload-76888d9cc9" 39 | }, 40 | "replicas": { 41 | "new": 1 42 | } 43 | } 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/supported-events/deployments/scale-out.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Scale Out 4 | parent: Deployments 5 | grand_parent: Supported Events 6 | --- 7 | 8 | ## Scale Out (Deployment) 9 | 10 | ![Availability Badge](https://img.shields.io/badge/Available%20Starting-v0.2.0-green.svg) 11 | 12 | This event represents a Deployment that is scaling out. 13 | 14 | ### Event Type 15 | 16 | `Kubernetes.Autoscaling.Deployment.V1.ScaleOut` 17 | 18 | ### Example 19 | 20 | ```json 21 | { 22 | "specversion": "1.0", 23 | "type": "Kubernetes.Autoscaling.Deployment.V1.ScaleOut", 24 | "source": "http://kubernetes/core/controllers/deployment", 25 | "id": "2bee1da4-d922-4459-b0f8-e789825f6bad", 26 | "time": "2021-04-16T06:42:49.8560883Z", 27 | "subject": "/local-cluster/namespaces/monitoring/deployments/k8s-event-grid-bridge-workload", 28 | "datacontenttype": "application/json", 29 | "data": { 30 | "deployment": { 31 | "name": "k8s-event-grid-bridge-workload", 32 | "namespace": "monitoring", 33 | "labels": { 34 | "app": "k8s-event-grid-bridge" 35 | } 36 | }, 37 | "replicaSet": { 38 | "name": "k8s-event-grid-bridge-workload-76888d9cc9" 39 | }, 40 | "replicas": { 41 | "new": 10 42 | } 43 | } 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/walkthroughs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Walkthroughs 4 | permalink: /walkthroughs/ 5 | has_children: true 6 | has_toc: true 7 | nav_order: 6 8 | --- 9 | 10 | Here are some walkthroughs that help you use Kubernetes Event Grid Bridge. 11 | -------------------------------------------------------------------------------- /events/KEDA/KEDAScaleTargetActivated.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "count": 1, 4 | "eventTime": null, 5 | "firstTimestamp": "2021-02-12T20:37:18Z", 6 | "involvedObject": { 7 | "apiVersion": "keda.sh/v1alpha1", 8 | "kind": "ScaledObject", 9 | "name": "demo-worker", 10 | "namespace": "foo", 11 | "resourceVersion": "2016120", 12 | "uid": "1dac27a7-7d0f-48a9-8688-12b9fb47ff82" 13 | }, 14 | "kind": "Event", 15 | "lastTimestamp": "2021-02-12T20:37:18Z", 16 | "message": "Scaled foo/demo-worker from 0 to 1", 17 | "metadata": { 18 | "creationTimestamp": "2021-02-12T20:37:18Z", 19 | "managedFields": [ 20 | { 21 | "apiVersion": "v1", 22 | "fieldsType": "FieldsV1", 23 | "manager": "keda", 24 | "operation": "Update", 25 | "time": "2021-02-12T20:37:18Z" 26 | } 27 | ], 28 | "name": "demo-worker.16631a82460cb2b7", 29 | "namespace": "foo", 30 | "resourceVersion": "2016292", 31 | "selfLink": "/api/v1/namespaces/foo/events/demo-worker.16631a82460cb2b7", 32 | "uid": "040abcd3-3355-4715-ae6f-26bace8b9d47" 33 | }, 34 | "reason": "KEDAScaleTargetActivated", 35 | "reportingComponent": "", 36 | "reportingInstance": "", 37 | "source": { 38 | "component": "keda-operator" 39 | }, 40 | "type": "Normal" 41 | } -------------------------------------------------------------------------------- /events/KEDA/KEDAScaleTargetDeactivated.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "count": 1, 4 | "eventTime": null, 5 | "firstTimestamp": "2021-02-12T20:37:38Z", 6 | "involvedObject": { 7 | "apiVersion": "keda.sh/v1alpha1", 8 | "kind": "ScaledObject", 9 | "name": "demo-worker", 10 | "namespace": "foo", 11 | "resourceVersion": "2016293", 12 | "uid": "1dac27a7-7d0f-48a9-8688-12b9fb47ff82" 13 | }, 14 | "kind": "Event", 15 | "lastTimestamp": "2021-02-12T20:37:38Z", 16 | "message": "Deactivated foo/demo-worker from 1 to 0", 17 | "metadata": { 18 | "creationTimestamp": "2021-02-12T20:37:38Z", 19 | "managedFields": [ 20 | { 21 | "apiVersion": "v1", 22 | "fieldsType": "FieldsV1", 23 | "manager": "keda", 24 | "operation": "Update", 25 | "time": "2021-02-12T20:37:38Z" 26 | } 27 | ], 28 | "name": "demo-worker.16631a86f8a0646d", 29 | "namespace": "foo", 30 | "resourceVersion": "2016372", 31 | "selfLink": "/api/v1/namespaces/foo/events/demo-worker.16631a86f8a0646d", 32 | "uid": "424c5689-21ec-45e9-8105-0ae5cb4bf874" 33 | }, 34 | "reason": "KEDAScaleTargetDeactivated", 35 | "reportingComponent": "", 36 | "reportingInstance": "", 37 | "source": { 38 | "component": "keda-operator" 39 | }, 40 | "type": "Normal" 41 | } -------------------------------------------------------------------------------- /events/KEDA/KEDAScalerFailed.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "count": 1, 4 | "eventTime": null, 5 | "firstTimestamp": "2021-02-12T20:42:20Z", 6 | "involvedObject": { 7 | "apiVersion": "keda.sh/v1alpha1", 8 | "kind": "ScaledObject", 9 | "name": "demo-worker", 10 | "namespace": "foo", 11 | "resourceVersion": "2016373", 12 | "uid": "1dac27a7-7d0f-48a9-8688-12b9fb47ff82" 13 | }, 14 | "kind": "Event", 15 | "lastTimestamp": "2021-02-12T20:42:20Z", 16 | "message": "-\u003e github.com/Azure/azure-storage-queue-go/azqueue.newStorageError, /go/pkg/mod/github.com/!azure/azure-storage-queue-go@v0.0.0-20191125232315-636801874cdd/azqueue/zc_storage_error.go:42\n===== RESPONSE ERROR (ServiceCode=AuthenticationFailed) =====\nDescription=Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:a765bfd5-5003-0074-1a7f-01ef55000000\nTime:2021-02-12T20:42:20.3372554Z, Details: \n AuthenticationErrorDetail: The MAC signature found in the HTTP request 'PxtGA2B+o/LIu5Lz5k9Hj6X9EKqp9gQmlnEBE9j+Fws=' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-client-request-id:d98a0219-7b32-458a-629c-f43808e3128f\nx-ms-date:Fri, 12 Feb 2021 20:42:20 GMT\nx-ms-version:2018-03-28\n/ahmelsbugbashstorage/js-queue-items\ncomp:metadata\ntimeout:61'.\n Code: AuthenticationFailed\n GET https://ahmelsbugbashstorage.queue.core.windows.net/js-queue-items?comp=metadata\u0026timeout=61\n Authorization: REDACTED\n User-Agent: [Azure-Storage/0.3 (go1.15.6; linux)]\n X-Ms-Client-Request-Id: [d98a0219-7b32-458a-629c-f43808e3128f]\n X-Ms-Date: [Fri, 12 Feb 2021 20:42:20 GMT]\n X-Ms-Version: [2018-03-28]\n --------------------------------------------------------------------------------\n RESPONSE Status: 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\n Content-Length: [750]\n Content-Type: [application/xml]\n Date: [Fri, 12 Feb 2021 20:42:20 GMT]\n Server: [Microsoft-HTTPAPI/2.0]\n X-Ms-Error-Code: [AuthenticationFailed]\n X-Ms-Request-Id: [a765bfd5-5003-0074-1a7f-01ef55000000]\n\n\n", 17 | "metadata": { 18 | "creationTimestamp": "2021-02-12T20:42:20Z", 19 | "managedFields": [ 20 | { 21 | "apiVersion": "v1", 22 | "fieldsType": "FieldsV1", 23 | "manager": "keda", 24 | "operation": "Update", 25 | "time": "2021-02-12T20:42:20Z" 26 | } 27 | ], 28 | "name": "demo-worker.16631ac897e95e20", 29 | "namespace": "foo", 30 | "resourceVersion": "2017169", 31 | "selfLink": "/api/v1/namespaces/foo/events/demo-worker.16631ac897e95e20", 32 | "uid": "a260a113-c1a7-4acb-9764-3c50dfaf3ec4" 33 | }, 34 | "reason": "KEDAScalerFailed", 35 | "reportingComponent": "", 36 | "reportingInstance": "", 37 | "source": { 38 | "component": "keda-operator" 39 | }, 40 | "type": "Warning" 41 | } -------------------------------------------------------------------------------- /events/KEDA/KEDAScalersStarted.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "count": 1, 4 | "eventTime": null, 5 | "firstTimestamp": "2021-02-12T20:36:17Z", 6 | "involvedObject": { 7 | "apiVersion": "keda.sh/v1alpha1", 8 | "kind": "ScaledObject", 9 | "name": "demo-worker", 10 | "namespace": "foo", 11 | "resourceVersion": "2016113", 12 | "uid": "1dac27a7-7d0f-48a9-8688-12b9fb47ff82" 13 | }, 14 | "kind": "Event", 15 | "lastTimestamp": "2021-02-12T20:36:17Z", 16 | "message": "Started scalers watch", 17 | "metadata": { 18 | "creationTimestamp": "2021-02-12T20:36:17Z", 19 | "managedFields": [ 20 | { 21 | "apiVersion": "v1", 22 | "fieldsType": "FieldsV1", 23 | "manager": "keda", 24 | "operation": "Update", 25 | "time": "2021-02-12T20:36:17Z" 26 | } 27 | ], 28 | "name": "demo-worker.16631a742c03be11", 29 | "namespace": "foo", 30 | "resourceVersion": "2016116", 31 | "selfLink": "/api/v1/namespaces/foo/events/demo-worker.16631a742c03be11", 32 | "uid": "2c72fc0f-e645-4107-ad9a-eb5bb43d611e" 33 | }, 34 | "reason": "KEDAScalersStarted", 35 | "reportingComponent": "", 36 | "reportingInstance": "", 37 | "source": { 38 | "component": "keda-operator" 39 | }, 40 | "type": "Normal" 41 | } -------------------------------------------------------------------------------- /events/KEDA/ScaledObjectReady.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "count": 1, 4 | "eventTime": null, 5 | "firstTimestamp": "2021-02-12T20:36:17Z", 6 | "involvedObject": { 7 | "apiVersion": "keda.sh/v1alpha1", 8 | "kind": "ScaledObject", 9 | "name": "demo-worker", 10 | "namespace": "foo", 11 | "resourceVersion": "2016113", 12 | "uid": "1dac27a7-7d0f-48a9-8688-12b9fb47ff82" 13 | }, 14 | "kind": "Event", 15 | "lastTimestamp": "2021-02-12T20:36:17Z", 16 | "message": "ScaledObject is ready for scaling", 17 | "metadata": { 18 | "creationTimestamp": "2021-02-12T20:36:17Z", 19 | "managedFields": [ 20 | { 21 | "apiVersion": "v1", 22 | "fieldsType": "FieldsV1", 23 | "manager": "keda", 24 | "operation": "Update", 25 | "time": "2021-02-12T20:36:17Z" 26 | } 27 | ], 28 | "name": "demo-worker.16631a742c0442e1", 29 | "namespace": "foo", 30 | "resourceVersion": "2016119", 31 | "selfLink": "/api/v1/namespaces/foo/events/demo-worker.16631a742c0442e1", 32 | "uid": "ed73fd4b-7bf2-461f-b1ed-84746efbcf82" 33 | }, 34 | "reason": "ScaledObjectReady", 35 | "reportingComponent": "", 36 | "reportingInstance": "", 37 | "source": { 38 | "component": "keda-operator" 39 | }, 40 | "type": "Normal" 41 | } -------------------------------------------------------------------------------- /events/cluster-autoscaler/NotTriggerScaleUp.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-4vrz4.1663dc76b9431e4a", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-4vrz4.1663dc76b9431e4a", 6 | "uid": "263589b2-eb17-4cdf-84b0-632e2431440f", 7 | "resourceVersion": "10119624", 8 | "creationTimestamp": "2021-02-15T07:52:10Z", 9 | "managedFields": [ 10 | { 11 | "manager": "cluster-autoscaler", 12 | "operation": "Update", 13 | "apiVersion": "v1", 14 | "time": "2021-02-15T07:52:10Z" 15 | } 16 | ] 17 | }, 18 | "reason": "NotTriggerScaleUp", 19 | "message": "pod didn't trigger scale-up (it wouldn't fit if a new node is added): 1 max node group size reached", 20 | "source": { 21 | "component": "cluster-autoscaler" 22 | }, 23 | "firstTimestamp": "2021-02-15T07:51:34Z", 24 | "lastTimestamp": "2021-02-15T07:51:34Z", 25 | "count": 1, 26 | "type": "Normal", 27 | "eventTime": null, 28 | "reportingComponent": "", 29 | "reportingInstance": "", 30 | "involvedObject": { 31 | "kind": "Pod", 32 | "namespace": "default", 33 | "name": "nginx-6799fc88d8-4vrz4", 34 | "uid": "836e5705-f54c-4303-97b4-6af3cf3e6230", 35 | "apiVersion": "v1", 36 | "resourceVersion": "10118810", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/cluster-autoscaler/ScaleDown.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000004.1663d8e3919db247", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000004.1663d8e3919db247", 6 | "uid": "0e1e1f9c-5920-4c82-b702-f8abf249ca45", 7 | "resourceVersion": "10105703", 8 | "creationTimestamp": "2021-02-15T06:46:03Z", 9 | "managedFields": [ 10 | { 11 | "manager": "cluster-autoscaler", 12 | "operation": "Update", 13 | "apiVersion": "v1", 14 | "time": "2021-02-15T06:46:03Z" 15 | } 16 | ] 17 | }, 18 | "reason": "ScaleDown", 19 | "message": "node removed by cluster autoscaler", 20 | "source": { 21 | "component": "cluster-autoscaler" 22 | }, 23 | "firstTimestamp": "2021-02-15T06:46:03Z", 24 | "lastTimestamp": "2021-02-15T06:46:03Z", 25 | "count": 1, 26 | "type": "Normal", 27 | "eventTime": null, 28 | "reportingComponent": "", 29 | "reportingInstance": "", 30 | "involvedObject": {} 31 | } -------------------------------------------------------------------------------- /events/cluster-autoscaler/ScaleDownEmpty.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "cluster-autoscaler-status.1663d8e388c6e362", 4 | "namespace": "kube-system", 5 | "selfLink": "/api/v1/namespaces/kube-system/events/cluster-autoscaler-status.1663d8e388c6e362", 6 | "uid": "d07ae469-5d73-494f-8085-edd2c1916c25", 7 | "resourceVersion": "10105701", 8 | "creationTimestamp": "2021-02-15T06:46:03Z", 9 | "managedFields": [ 10 | { 11 | "manager": "cluster-autoscaler", 12 | "operation": "Update", 13 | "apiVersion": "v1", 14 | "time": "2021-02-15T06:46:03Z" 15 | } 16 | ] 17 | }, 18 | "reason": "ScaleDownEmpty", 19 | "message": "Scale-down: removing empty node aks-agentpool-11593772-vmss000004", 20 | "source": { 21 | "component": "cluster-autoscaler" 22 | }, 23 | "firstTimestamp": "2021-02-15T06:46:03Z", 24 | "lastTimestamp": "2021-02-15T06:46:03Z", 25 | "count": 1, 26 | "type": "Normal", 27 | "eventTime": null, 28 | "reportingComponent": "", 29 | "reportingInstance": "", 30 | "involvedObject": { 31 | "kind": "ConfigMap", 32 | "namespace": "kube-system", 33 | "name": "cluster-autoscaler-status", 34 | "uid": "4bef47ef-d436-4ed8-8f42-9a5a9f6175da", 35 | "apiVersion": "v1", 36 | "resourceVersion": "10105672" 37 | } 38 | } -------------------------------------------------------------------------------- /events/cluster-autoscaler/ScaledUpGroup.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "cluster-autoscaler-status.1663d838f8750ee2", 4 | "namespace": "kube-system", 5 | "selfLink": "/api/v1/namespaces/kube-system/events/cluster-autoscaler-status.1663d838f8750ee2", 6 | "uid": "9f64fc58-a3b5-4dbf-bd9e-d493b70aae42", 7 | "resourceVersion": "10102658", 8 | "creationTimestamp": "2021-02-15T06:33:50Z", 9 | "managedFields": [ 10 | { 11 | "manager": "cluster-autoscaler", 12 | "operation": "Update", 13 | "apiVersion": "v1", 14 | "time": "2021-02-15T06:33:50Z" 15 | } 16 | ] 17 | }, 18 | "reason": "ScaledUpGroup", 19 | "message": "Scale-up: setting group aks-agentpool-11593772-vmss size to 2", 20 | "source": { 21 | "component": "cluster-autoscaler" 22 | }, 23 | "firstTimestamp": "2021-02-15T06:33:50Z", 24 | "lastTimestamp": "2021-02-15T06:33:50Z", 25 | "count": 1, 26 | "type": "Normal", 27 | "eventTime": null, 28 | "reportingComponent": "", 29 | "reportingInstance": "", 30 | "involvedObject": { 31 | "kind": "ConfigMap", 32 | "namespace": "kube-system", 33 | "name": "cluster-autoscaler-status", 34 | "uid": "4bef47ef-d436-4ed8-8f42-9a5a9f6175da", 35 | "apiVersion": "v1", 36 | "resourceVersion": "10102264" 37 | } 38 | } -------------------------------------------------------------------------------- /events/cluster-autoscaler/TriggeredScaleUp.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-8vp5l.1663d839287f874d", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-8vp5l.1663d839287f874d", 6 | "uid": "71b2ee14-4845-4514-9b86-08ab74ebc294", 7 | "resourceVersion": "10102671", 8 | "creationTimestamp": "2021-02-15T06:33:51Z", 9 | "managedFields": [ 10 | { 11 | "manager": "cluster-autoscaler", 12 | "operation": "Update", 13 | "apiVersion": "v1", 14 | "time": "2021-02-15T06:33:51Z" 15 | } 16 | ] 17 | }, 18 | "reason": "TriggeredScaleUp", 19 | "message": "pod triggered scale-up: [{aks-agentpool-11593772-vmss 1->2 (max: 2)}]", 20 | "source": { 21 | "component": "cluster-autoscaler" 22 | }, 23 | "firstTimestamp": "2021-02-15T06:33:51Z", 24 | "lastTimestamp": "2021-02-15T06:33:51Z", 25 | "count": 1, 26 | "type": "Normal", 27 | "eventTime": null, 28 | "reportingComponent": "", 29 | "reportingInstance": "", 30 | "involvedObject": { 31 | "kind": "Pod", 32 | "namespace": "default", 33 | "name": "nginx-6799fc88d8-8vp5l", 34 | "uid": "b9ec3ac9-5055-4880-aaec-ddce65b26774", 35 | "apiVersion": "v1", 36 | "resourceVersion": "10102618", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/ContainerStarted.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-rxw8h.165c5a002bd7cdd7", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-rxw8h.165c5a002bd7cdd7", 6 | "uid": "51ff5002-2f5a-4da4-a12d-b4b9c814b6f2", 7 | "resourceVersion": "4320801", 8 | "creationTimestamp": "2021-01-21T20:42:03Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:42:03Z" 14 | }] 15 | }, 16 | "reason": "Started", 17 | "message": "Started container nginx", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-21T20:42:03Z", 23 | "lastTimestamp": "2021-01-21T20:42:03Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "nginx-6799fc88d8-rxw8h", 33 | "uid": "207dfebb-c80b-48d9-9bdf-710458a025c9", 34 | "apiVersion": "v1", 35 | "resourceVersion": "4320760", 36 | "fieldPath": "spec.containers{nginx}", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/FailedCreatePodSandBox.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "frontend-dtjf5.1675f3de40d4037d", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/frontend-dtjf5.1675f3de40d4037d", 6 | "uid": "ac5314ce-6f92-4f5a-a2d7-f51316105126", 7 | "resourceVersion": "24231421", 8 | "creationTimestamp": "2021-04-15T06:22:57Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-04-15T06:22:57Z" 14 | }] 15 | }, 16 | "reason": "FailedCreatePodSandBox", 17 | "message": "Failed to create pod sandbox: rpc error: code = Unknown desc = failed to start sandbox container task \"0a82fde7c4390a9050b0381a1be0e71671b38e46c25f9f7e0837f283f3bac9ad\": OCI runtime start failed: cannot start a container that has stopped: unknown", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-04-15T06:22:57Z", 23 | "lastTimestamp": "2021-04-15T06:22:57Z", 24 | "count": 1, 25 | "type": "Warning", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "frontend-dtjf5", 33 | "uid": "94c9fbb6-e0ae-4543-86e1-18f139ae2db1", 34 | "apiVersion": "v1", 35 | "resourceVersion": "24231333", 36 | "labels": { 37 | "tier": "frontend" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /events/core/ImagePulled.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-rxw8h.165c5a00013113ad", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-rxw8h.165c5a00013113ad", 6 | "uid": "d1895894-efdb-494b-b28e-37be9b67638b", 7 | "resourceVersion": "4320797", 8 | "creationTimestamp": "2021-01-21T20:42:02Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:42:02Z" 14 | }] 15 | }, 16 | "reason": "Pulled", 17 | "message": "Successfully pulled image \"nginx\" in 1.418931273s", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-21T20:42:02Z", 23 | "lastTimestamp": "2021-01-21T20:42:02Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "nginx-6799fc88d8-rxw8h", 33 | "uid": "207dfebb-c80b-48d9-9bdf-710458a025c9", 34 | "apiVersion": "v1", 35 | "resourceVersion": "4320760", 36 | "fieldPath": "spec.containers{nginx}", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/InvalidDiskCapacity.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c88750cdf8085", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c88750cdf8085", 6 | "uid": "74fb7c94-e315-462e-8922-ef2b225244f5", 7 | "resourceVersion": "4457508", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "InvalidDiskCapacity", 17 | "message": "invalid capacity 0 on image filesystem", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:23Z", 23 | "lastTimestamp": "2021-01-22T10:53:23Z", 24 | "count": 1, 25 | "type": "Warning", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/KillingContainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-sthns.165c59c2a112274c", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-sthns.165c59c2a112274c", 6 | "uid": "9248235e-0971-45b9-a505-ebaa1c6eec5c", 7 | "resourceVersion": "4320047", 8 | "creationTimestamp": "2021-01-21T20:37:39Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:37:39Z" 14 | }] 15 | }, 16 | "reason": "Killing", 17 | "message": "Stopping container nginx", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-21T20:37:39Z", 23 | "lastTimestamp": "2021-01-21T20:37:39Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "nginx-6799fc88d8-sthns", 33 | "uid": "c8c3901f-630b-4c0b-82be-b4e64bb564a8", 34 | "apiVersion": "v1", 35 | "resourceVersion": "3719461", 36 | "fieldPath": "spec.containers{nginx}", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/KillingPod.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-rxw8h.165c5ac810bc568b", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-rxw8h.165c5ac810bc568b", 6 | "uid": "05e07fec-c7c8-4539-8618-ee5eb6c445a7", 7 | "resourceVersion": "4323129", 8 | "creationTimestamp": "2021-01-21T20:56:22Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:56:22Z" 14 | }] 15 | }, 16 | "reason": "Killing", 17 | "message": "Stopping container nginx", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-21T20:56:22Z", 23 | "lastTimestamp": "2021-01-21T20:56:22Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "nginx-6799fc88d8-rxw8h", 33 | "uid": "207dfebb-c80b-48d9-9bdf-710458a025c9", 34 | "apiVersion": "v1", 35 | "resourceVersion": "4320760", 36 | "fieldPath": "spec.containers{nginx}", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/NodeAllocatableEnforced.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c887517dda665", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c887517dda665", 6 | "uid": "f09c9ad8-1a60-40ad-a088-0396d0c4f11a", 7 | "resourceVersion": "4457525", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "NodeAllocatableEnforced", 17 | "message": "Updated Node Allocatable limit across pods", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:23Z", 23 | "lastTimestamp": "2021-01-22T10:53:23Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/NodeHasNoDiskPressure.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c8875140a4615", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c8875140a4615", 6 | "uid": "9b871d7f-8e31-4d2b-a013-2edd2b14026e", 7 | "resourceVersion": "4457521", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "NodeHasNoDiskPressure", 17 | "message": "Node aks-agentpool-11593772-vmss000001 status is now: NodeHasNoDiskPressure", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:23Z", 23 | "lastTimestamp": "2021-01-22T10:53:23Z", 24 | "count": 2, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/NodeHasSufficientMemory.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c8875140a134d", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c8875140a134d", 6 | "uid": "026ea61e-be83-4e79-ba02-b6160040ccd7", 7 | "resourceVersion": "4457518", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "NodeHasSufficientMemory", 17 | "message": "Node aks-agentpool-11593772-vmss000001 status is now: NodeHasSufficientMemory", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:23Z", 23 | "lastTimestamp": "2021-01-22T10:53:23Z", 24 | "count": 2, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/NodeHasSufficientPID.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c8875140a648d", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c8875140a648d", 6 | "uid": "5b4b73aa-a235-4c3f-9216-cad4d6140d6c", 7 | "resourceVersion": "4457523", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "NodeHasSufficientPID", 17 | "message": "Node aks-agentpool-11593772-vmss000001 status is now: NodeHasSufficientPID", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:23Z", 23 | "lastTimestamp": "2021-01-22T10:53:23Z", 24 | "count": 2, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/NodeReady.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c88776df8b259", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c88776df8b259", 6 | "uid": "fbc587f8-ec0b-48c8-80be-47a0bbb431ee", 7 | "resourceVersion": "4457562", 8 | "creationTimestamp": "2021-01-22T10:53:33Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:33Z" 14 | }] 15 | }, 16 | "reason": "NodeReady", 17 | "message": "Node aks-agentpool-11593772-vmss000001 status is now: NodeReady", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:33Z", 23 | "lastTimestamp": "2021-01-22T10:53:33Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/PodScheduled.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-rxw8h.165c59ff7aaf442c", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-rxw8h.165c59ff7aaf442c", 6 | "uid": "5f294933-3537-4ebe-ab9a-7226ff86cd2f", 7 | "resourceVersion": "4320762", 8 | "creationTimestamp": "2021-01-21T20:42:00Z", 9 | "managedFields": [{ 10 | "manager": "kube-scheduler", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:42:00Z" 14 | }] 15 | }, 16 | "reason": "Scheduled", 17 | "message": "Successfully assigned default/nginx-6799fc88d8-rxw8h to aks-agentpool-11593772-vmss000000", 18 | "source": { 19 | "component": "default-scheduler" 20 | }, 21 | "firstTimestamp": "2021-01-21T20:42:00Z", 22 | "lastTimestamp": "2021-01-21T20:42:00Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "Pod", 30 | "namespace": "default", 31 | "name": "nginx-6799fc88d8-rxw8h", 32 | "uid": "207dfebb-c80b-48d9-9bdf-710458a025c9", 33 | "apiVersion": "v1", 34 | "resourceVersion": "4320758", 35 | "labels": { 36 | "app": "nginx", 37 | "pod-template-hash": "6799fc88d8" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /events/core/PodUnhealthyDueToHealthProbe.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "coredns-autoscaler-5b6cbd75d7-rf47t.1675f3df24a918d1", 4 | "namespace": "kube-system", 5 | "selfLink": "/api/v1/namespaces/kube-system/events/coredns-autoscaler-5b6cbd75d7-rf47t.1675f3df24a918d1", 6 | "uid": "fb4abf18-3e36-49eb-8a22-9dbe04c8a7d3", 7 | "resourceVersion": "24231436", 8 | "creationTimestamp": "2021-04-15T06:23:00Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-04-15T06:23:00Z" 14 | }] 15 | }, 16 | "reason": "Unhealthy", 17 | "message": "Liveness probe failed: Get \"http://10.244.0.7:8080/last-poll\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-04-15T06:23:00Z", 23 | "lastTimestamp": "2021-04-15T06:23:00Z", 24 | "count": 1, 25 | "type": "Warning", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "kube-system", 32 | "name": "coredns-autoscaler-5b6cbd75d7-rf47t", 33 | "uid": "21db1050-abb4-47e3-bb0c-c333bc80c225", 34 | "apiVersion": "v1", 35 | "resourceVersion": "840", 36 | "fieldPath": "spec.containers{autoscaler}", 37 | "labels": { 38 | "k8s-app": "coredns-autoscaler", 39 | "pod-template-hash": "5b6cbd75d7" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/PodUnhealthyDueToReadinessProbe.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "metrics-server-77c8679d7d-tsdpq.165910f5e7077e3c", 4 | "namespace": "kube-system", 5 | "selfLink": "/api/v1/namespaces/kube-system/events/metrics-server-77c8679d7d-tsdpq.165910f5e7077e3c", 6 | "uid": "f43d0bd2-2b95-48d3-a505-6f800c96cea6", 7 | "resourceVersion": "24231435", 8 | "creationTimestamp": "2021-04-15T06:23:00Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-04-15T06:23:00Z" 14 | }] 15 | }, 16 | "reason": "Unhealthy", 17 | "message": "Readiness probe failed: Get \"https://10.244.0.3:443/healthz\": net/http: request canceled (Client.Timeout exceeded while awaiting headers)", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-11T03:49:50Z", 23 | "lastTimestamp": "2021-04-15T06:23:00Z", 24 | "count": 19, 25 | "type": "Warning", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "kube-system", 32 | "name": "metrics-server-77c8679d7d-tsdpq", 33 | "uid": "3e7da7be-4c5a-47cf-8613-719c0afde77b", 34 | "apiVersion": "v1", 35 | "resourceVersion": "836", 36 | "fieldPath": "spec.containers{metrics-server}", 37 | "labels": { 38 | "k8s-app": "metrics-server", 39 | "pod-template-hash": "77c8679d7d" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/PodVolumeMountFailed.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "frontend-zshp9.1675f3e79ed67fa5", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/frontend-zshp9.1675f3e79ed67fa5", 6 | "uid": "56f2cb2e-4812-48b0-ad3e-556bed8cc191", 7 | "resourceVersion": "24231542", 8 | "creationTimestamp": "2021-04-15T06:23:37Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-04-15T06:23:37Z" 14 | }] 15 | }, 16 | "reason": "Failed", 17 | "message": "Error: cannot find volume \"default-token-wjk8j\" to mount into container \"php-redis\"", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-04-15T06:23:37Z", 23 | "lastTimestamp": "2021-04-15T06:23:37Z", 24 | "count": 1, 25 | "type": "Warning", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "frontend-zshp9", 33 | "uid": "cd72f718-d40f-47f0-b15e-6dd360e69f34", 34 | "apiVersion": "v1", 35 | "resourceVersion": "24231332", 36 | "fieldPath": "spec.containers{php-redis}", 37 | "labels": { 38 | "tier": "frontend" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /events/core/PullingImage.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8-rxw8h.165c59ffac9da81b", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8-rxw8h.165c59ffac9da81b", 6 | "uid": "bf81f475-ed18-4ba5-804b-b1677e805f63", 7 | "resourceVersion": "4320788", 8 | "creationTimestamp": "2021-01-21T20:42:01Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:42:01Z" 14 | }] 15 | }, 16 | "reason": "Pulling", 17 | "message": "Pulling image \"nginx\"", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000000" 21 | }, 22 | "firstTimestamp": "2021-01-21T20:42:01Z", 23 | "lastTimestamp": "2021-01-21T20:42:01Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": { 30 | "kind": "Pod", 31 | "namespace": "default", 32 | "name": "nginx-6799fc88d8-rxw8h", 33 | "uid": "207dfebb-c80b-48d9-9bdf-710458a025c9", 34 | "apiVersion": "v1", 35 | "resourceVersion": "4320760", 36 | "fieldPath": "spec.containers{nginx}", 37 | "labels": { 38 | "app": "nginx", 39 | "pod-template-hash": "6799fc88d8" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /events/core/RegisteredNode.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c887543c9c6b2", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c887543c9c6b2", 6 | "uid": "06fb5e43-f1c6-4edb-af45-cb1083c4ad66", 7 | "resourceVersion": "4457532", 8 | "creationTimestamp": "2021-01-22T10:53:23Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:23Z" 14 | }] 15 | }, 16 | "reason": "RegisteredNode", 17 | "message": "Node aks-agentpool-11593772-vmss000001 event: Registered Node aks-agentpool-11593772-vmss000001 in Controller", 18 | "source": { 19 | "component": "node-controller" 20 | }, 21 | "firstTimestamp": "2021-01-22T10:53:23Z", 22 | "lastTimestamp": "2021-01-22T10:53:23Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": {} 29 | } -------------------------------------------------------------------------------- /events/core/RemovingNode.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c8cff2a11aa2b", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c8cff2a11aa2b", 6 | "uid": "e2ba6a46-ebd8-4633-a44f-49158dfcf5ed", 7 | "resourceVersion": "4471400", 8 | "creationTimestamp": "2021-01-22T12:16:34Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T12:16:34Z" 14 | }] 15 | }, 16 | "reason": "RemovingNode", 17 | "message": "Node aks-agentpool-11593772-vmss000001 event: Removing Node aks-agentpool-11593772-vmss000001 from Controller", 18 | "source": { 19 | "component": "node-controller" 20 | }, 21 | "firstTimestamp": "2021-01-22T12:16:34Z", 22 | "lastTimestamp": "2021-01-22T12:16:34Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": {} 29 | } -------------------------------------------------------------------------------- /events/core/ScalingReplicaSetDown.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "k8s-event-grid-bridge-workload.1656cffa3223676d", 4 | "namespace": "monitoring", 5 | "selfLink": "/api/v1/namespaces/monitoring/events/k8s-event-grid-bridge-workload.1656cffa3223676d", 6 | "uid": "f5b5c92f-86c3-454f-a269-287dc1c46e62", 7 | "resourceVersion": "68019", 8 | "creationTimestamp": "2021-01-03T19:36:30Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-03T19:36:30Z" 14 | } 15 | ] 16 | }, 17 | "reason": "ScalingReplicaSet", 18 | "message": "Scaled down replica set k8s-event-grid-bridge-workload-76888d9cc9 to 10", 19 | "source": { 20 | "component": "deployment-controller" 21 | }, 22 | "firstTimestamp": "2021-01-03T19:36:30Z", 23 | "lastTimestamp": "2021-01-03T19:36:30Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "Deployment", 30 | "namespace": "monitoring", 31 | "name": "k8s-event-grid-bridge-workload", 32 | "uid": "4f3b68fc-126f-4df3-8961-c70d4d18f045", 33 | "apiVersion": "apps/v1", 34 | "resourceVersion": "68017", 35 | "labels": { 36 | "app": "k8s-event-grid-bridge" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /events/core/ScalingReplicaSetUp.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "k8s-event-grid-bridge-workload.1656cffa3223676d", 4 | "namespace": "monitoring", 5 | "selfLink": "/api/v1/namespaces/monitoring/events/k8s-event-grid-bridge-workload.1656cffa3223676d", 6 | "uid": "f5b5c92f-86c3-454f-a269-287dc1c46e62", 7 | "resourceVersion": "68019", 8 | "creationTimestamp": "2021-01-03T19:36:30Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-03T19:36:30Z" 14 | } 15 | ] 16 | }, 17 | "reason": "ScalingReplicaSet", 18 | "message": "Scaled up replica set k8s-event-grid-bridge-workload-76888d9cc9 to 20", 19 | "source": { 20 | "component": "deployment-controller" 21 | }, 22 | "firstTimestamp": "2021-01-03T19:36:30Z", 23 | "lastTimestamp": "2021-01-03T19:36:30Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "Deployment", 30 | "namespace": "monitoring", 31 | "name": "k8s-event-grid-bridge-workload", 32 | "uid": "4f3b68fc-126f-4df3-8961-c70d4d18f045", 33 | "apiVersion": "apps/v1", 34 | "resourceVersion": "68017", 35 | "labels": { 36 | "app": "k8s-event-grid-bridge" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /events/core/StartingKubelet.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "aks-agentpool-11593772-vmss000001.165c8875075aabc1", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/aks-agentpool-11593772-vmss000001.165c8875075aabc1", 6 | "uid": "65e0f05b-3442-4116-bb94-d8dc094d7391", 7 | "resourceVersion": "4457507", 8 | "creationTimestamp": "2021-01-22T10:53:22Z", 9 | "managedFields": [{ 10 | "manager": "kubelet", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:22Z" 14 | }] 15 | }, 16 | "reason": "Starting", 17 | "message": "Starting kubelet.", 18 | "source": { 19 | "component": "kubelet", 20 | "host": "aks-agentpool-11593772-vmss000001" 21 | }, 22 | "firstTimestamp": "2021-01-22T10:53:22Z", 23 | "lastTimestamp": "2021-01-22T10:53:22Z", 24 | "count": 1, 25 | "type": "Normal", 26 | "eventTime": null, 27 | "reportingComponent": "", 28 | "reportingInstance": "", 29 | "involvedObject": {} 30 | } -------------------------------------------------------------------------------- /events/core/SuccesfulCreate.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8.165c59ff7ad784cc", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8.165c59ff7ad784cc", 6 | "uid": "be7a918d-7b65-4035-8dc2-2df6fa2d569f", 7 | "resourceVersion": "4320764", 8 | "creationTimestamp": "2021-01-21T20:42:00Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:42:00Z" 14 | }] 15 | }, 16 | "reason": "SuccessfulCreate", 17 | "message": "Created pod: nginx-6799fc88d8-w9sn4", 18 | "source": { 19 | "component": "replicaset-controller" 20 | }, 21 | "firstTimestamp": "2021-01-21T20:42:00Z", 22 | "lastTimestamp": "2021-01-21T20:42:00Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "ReplicaSet", 30 | "namespace": "default", 31 | "name": "nginx-6799fc88d8", 32 | "uid": "7c8ff468-cd97-437c-9a39-0c323347b2bd", 33 | "apiVersion": "apps/v1", 34 | "resourceVersion": "4320754", 35 | "labels": { 36 | "app": "nginx", 37 | "pod-template-hash": "6799fc88d8" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /events/core/SuccessfulDelete.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "nginx-6799fc88d8.165c59c2a0d7ee33", 4 | "namespace": "default", 5 | "selfLink": "/api/v1/namespaces/default/events/nginx-6799fc88d8.165c59c2a0d7ee33", 6 | "uid": "85b8d337-ae2a-423b-8b32-44c6ab393842", 7 | "resourceVersion": "4320045", 8 | "creationTimestamp": "2021-01-21T20:37:39Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-21T20:37:39Z" 14 | }] 15 | }, 16 | "reason": "SuccessfulDelete", 17 | "message": "Deleted pod: nginx-6799fc88d8-sthns", 18 | "source": { 19 | "component": "replicaset-controller" 20 | }, 21 | "firstTimestamp": "2021-01-21T20:37:39Z", 22 | "lastTimestamp": "2021-01-21T20:37:39Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "ReplicaSet", 30 | "namespace": "default", 31 | "name": "nginx-6799fc88d8", 32 | "uid": "7c8ff468-cd97-437c-9a39-0c323347b2bd", 33 | "apiVersion": "apps/v1", 34 | "resourceVersion": "4320041", 35 | "labels": { 36 | "app": "nginx", 37 | "pod-template-hash": "6799fc88d8" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /events/core/UpdatedLoadBalancer.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "addon-http-application-routing-nginx-ingress.165c8877995dc876", 4 | "namespace": "kube-system", 5 | "selfLink": "/api/v1/namespaces/kube-system/events/addon-http-application-routing-nginx-ingress.165c8877995dc876", 6 | "uid": "78772889-2622-4858-b908-fbbbd4e00ef1", 7 | "resourceVersion": "4457573", 8 | "creationTimestamp": "2021-01-22T10:53:33Z", 9 | "managedFields": [{ 10 | "manager": "kube-controller-manager", 11 | "operation": "Update", 12 | "apiVersion": "v1", 13 | "time": "2021-01-22T10:53:33Z" 14 | }] 15 | }, 16 | "reason": "UpdatedLoadBalancer", 17 | "message": "Updated load balancer with new hosts", 18 | "source": { 19 | "component": "service-controller" 20 | }, 21 | "firstTimestamp": "2021-01-22T10:53:33Z", 22 | "lastTimestamp": "2021-01-22T10:53:33Z", 23 | "count": 1, 24 | "type": "Normal", 25 | "eventTime": null, 26 | "reportingComponent": "", 27 | "reportingInstance": "", 28 | "involvedObject": { 29 | "kind": "Service", 30 | "namespace": "kube-system", 31 | "name": "addon-http-application-routing-nginx-ingress", 32 | "uid": "787ca35a-9c87-43ce-8d27-406db610d319", 33 | "apiVersion": "v1", 34 | "resourceVersion": "542", 35 | "labels": { 36 | "addonmanager.kubernetes.io/mode": "Reconcile", 37 | "app": "addon-http-application-routing-nginx-ingress", 38 | "kubernetes.io/cluster-service": "true" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /examples/helm-chart.config.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | tag: experimental 3 | azure: 4 | storage: 5 | connectionString: 6 | eventGrid: 7 | topicUri: 8 | key: 9 | -------------------------------------------------------------------------------- /kubernetes-event-exporter-config.yml: -------------------------------------------------------------------------------- 1 | image: 2 | registry: docker.io 3 | repository: opsgenie/kubernetes-event-exporter 4 | tag: latest 5 | config: 6 | route: 7 | routes: 8 | - match: 9 | - receiver: "k8s-event-grid-bridge" 10 | receivers: 11 | - name: "k8s-event-grid-bridge" 12 | webhook: 13 | endpoint: "http://k8s-event-grid-bridge:8888/api/kubernetes/events/forward" 14 | headers: 15 | User-Agent: kube-event-exporter 1.0 -------------------------------------------------------------------------------- /media/schematics.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/media/schematics.pptx -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [Settings] 2 | # Added automatically by the Netlify CLI. It has no effect during normal 3 | # Git-backed deploys. 4 | ID = "bb0b527e-d494-4f14-902b-94457b42c5e2" 5 | 6 | # Settings in the [build] context are global and are applied to all contexts 7 | # unless otherwise overridden by more specific contexts. 8 | [build] 9 | # Directory to change to before starting a build. 10 | # This is where we will look for package.json/.nvmrc/etc. 11 | base = "docs/" 12 | 13 | # Directory (relative to root of your repo) that contains the deploy-ready 14 | # HTML files and assets generated by the build. 15 | publish = "_site" 16 | 17 | # Default build command. 18 | command = "jekyll build" 19 | 20 | # Directory with the lambda functions to deploy to AWS. 21 | # functions = "project/functions/" 22 | 23 | # Production context: all deploys from the Production branch set in your site's 24 | # deploy settings will inherit these settings. 25 | # [context.production] 26 | # publish = "output/" 27 | # command = "make publish" 28 | # environment = { ACCESS_TOKEN = "super secret", NODE_ENV = "8.0.1" } 29 | 30 | # Deploy Preview context: all deploys resulting from a pull/merge request will 31 | # inherit these settings. 32 | # [context.deploy-preview] 33 | # publish = "dist/" 34 | -------------------------------------------------------------------------------- /src/.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | .env 3 | .git 4 | .gitignore 5 | .vs 6 | .vscode 7 | */bin 8 | */obj 9 | **/.toolstarget -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Enums/HorizontalScaleDirection.cs: -------------------------------------------------------------------------------- 1 | namespace Kubernetes.EventGrid.Bridge.Contracts.Enums 2 | { 3 | public enum HorizontalScaleDirection 4 | { 5 | NotSpecified, 6 | In, 7 | Out 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Enums/KubernetesEventType.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace Kubernetes.EventGrid.Bridge.Contracts.Enums 4 | { 5 | public enum KubernetesEventType 6 | { 7 | Unspecified, 8 | [Description("Kubernetes.Events.Raw")] 9 | Raw, 10 | [Description("Kubernetes.Autoscaling.ClusterAutoscaler.V1.NodeGroup.ScaleOut")] 11 | ClusterAutoscalerScaleOut, 12 | [Description("Kubernetes.Autoscaling.Deployment.V1.ScaleIn")] 13 | DeploymentScaleIn, 14 | [Description("Kubernetes.Autoscaling.Deployment.V1.ScaleOut")] 15 | DeploymentScaleOut 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Events/ClusterAutoscaler/ClusterAutoscalerScaleEventPayload.cs: -------------------------------------------------------------------------------- 1 | namespace Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler 2 | { 3 | public class ClusterAutoscalerScaleEventPayload 4 | { 5 | public NodeGroupResizeInfo NodeGroup { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Events/ClusterAutoscaler/NewNodeGroupSizeInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler 3 | { 4 | public class NewNodeGroupSizeInfo 5 | { 6 | public int New { get; set; } 7 | public int Old { get; set; } 8 | public int Maximum { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Events/ClusterAutoscaler/NodeGroupResizeInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler 3 | { 4 | public class NodeGroupResizeInfo 5 | { 6 | public string Name { get; set; } 7 | public NewNodeGroupSizeInfo SizeInfo { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Events/Deployments/DeploymentScaleEventPayload.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Kubernetes.EventGrid.Bridge.Contracts.Events.Deployments 4 | { 5 | public class DeploymentScaleEventPayload 6 | { 7 | public DeploymentInfo Deployment { get; set; } 8 | public ReplicaSetInfo ReplicaSet { get; set; } 9 | public ReplicaInfo Replicas { get; set; } 10 | } 11 | 12 | public class DeploymentInfo 13 | { 14 | public string Name { get; set; } 15 | public string Namespace { get; set; } 16 | public Dictionary Labels { get; set; } = new Dictionary(); 17 | } 18 | 19 | public class ReplicaSetInfo 20 | { 21 | public string Name { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Events/Deployments/ReplicaInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Kubernetes.EventGrid.Bridge.Contracts.Events.Deployments 6 | { 7 | public class ReplicaInfo 8 | { 9 | public int New { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace Kubernetes.EventGrid.Bridge.Contracts.Extensions 5 | { 6 | public static class EnumExtensions 7 | { 8 | /// 9 | /// Gets the description for an enumeration value 10 | /// 11 | /// Provides the raw enum value when no default description is specified 12 | /// Enumeration value 13 | /// Default description to use when not annotated 14 | public static string GetDescription(this Enum enumValue, string defaultDescription = null) 15 | { 16 | var type = enumValue.GetType(); 17 | 18 | var rawEnumValue = enumValue.ToString(); 19 | var info = type.GetField(rawEnumValue); 20 | var descriptionAttributes = (DescriptionAttribute[]) info.GetCustomAttributes(typeof(DescriptionAttribute), false); 21 | 22 | if (descriptionAttributes.Length > 0) 23 | { 24 | return descriptionAttributes[0].Description; 25 | } 26 | 27 | return defaultDescription ?? rawEnumValue; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/Kubernetes.EventGrid.Bridge.Contracts.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | Contracts for events emitted by Kubernetes Event Grid Bridge. 7 | http://docs.k8s-event-grid-bridge.io/ 8 | https://github.com/tomkerkhove/k8s-event-grid-bridge 9 | git 10 | Kubernetes;Azure;Azure Event Grid;CloudEvents 11 | logo.png 12 | Tom Kerkhove 13 | LICENSE 14 | 15 | Tom Kerkhove 16 | Kubernetes Event Grid Bridge 17 | 18 | 19 | 20 | 21 | True 22 | 23 | 24 | 25 | True 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tom Kerkhove 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Contracts/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkerkhove/k8s-event-grid-bridge/d72f9f440c38be5c79429f7386f581079e97df0f/src/Kubernetes.EventGrid.Bridge.Contracts/logo.png -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/.dockerignore: -------------------------------------------------------------------------------- 1 | local.settings.json -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build 2 | WORKDIR /src 3 | COPY ["Kubernetes.EventGrid.Bridge.Host/Kubernetes.EventGrid.Bridge.Host.csproj", "Kubernetes.EventGrid.Bridge.Host/"] 4 | COPY ["Kubernetes.EventGrid.Core/Kubernetes.EventGrid.Core.csproj", "Kubernetes.EventGrid.Core/"] 5 | RUN dotnet restore "Kubernetes.EventGrid.Bridge.Host/Kubernetes.EventGrid.Bridge.Host.csproj" 6 | COPY . . 7 | WORKDIR "/src/Kubernetes.EventGrid.Bridge.Host" 8 | RUN dotnet build "Kubernetes.EventGrid.Bridge.Host.csproj" -c Release -o /app/build 9 | 10 | FROM build AS publish 11 | RUN dotnet publish "Kubernetes.EventGrid.Bridge.Host.csproj" -c Release -o /app/publish 12 | 13 | FROM mcr.microsoft.com/azure-functions/dotnet:3.0 AS runtime 14 | WORKDIR /home/site/wwwroot 15 | EXPOSE 80 16 | COPY --from=publish /app/publish . 17 | ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ 18 | AzureFunctionsJobHost__Logging__Console__IsEnabled=true -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/Kubernetes.EventGrid.Bridge.Host.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp3.1 4 | v3 5 | /home/site/wwwroot 6 | Linux 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | PreserveNewest 27 | 28 | 29 | PreserveNewest 30 | Never 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/KubernetesEventExporterFunction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using Arcus.EventGrid.Publishing.Interfaces; 4 | using CloudNative.CloudEvents; 5 | using GuardNet; 6 | using Kubernetes.EventGrid.Core.CloudEvents.Interfaces; 7 | using Kubernetes.EventGrid.Core.Kubernetes; 8 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 9 | using Microsoft.AspNetCore.Http; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.Azure.WebJobs; 12 | using Microsoft.Azure.WebJobs.Extensions.Http; 13 | using Microsoft.Extensions.Logging; 14 | using Serilog.Context; 15 | 16 | namespace Kubernetes.EventGrid.Bridge.Host 17 | { 18 | public class KubernetesEventExporterFunction 19 | { 20 | private readonly ILogger _logger; 21 | private readonly ICloudEventFactory _cloudEventFactory; 22 | private readonly IEventGridPublisher _eventGridPublisher; 23 | 24 | public KubernetesEventExporterFunction(ICloudEventFactory cloudEventFactory, IEventGridPublisher eventGridPublisher, ILogger logger) 25 | { 26 | Guard.NotNull(eventGridPublisher, nameof(eventGridPublisher)); 27 | Guard.NotNull(logger, nameof(logger)); 28 | 29 | _logger = logger; 30 | _cloudEventFactory = cloudEventFactory; 31 | _eventGridPublisher = eventGridPublisher; 32 | } 33 | 34 | [FunctionName("kubernetes-event-exporter")] 35 | public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, Route = "kubernetes/events/forward")] HttpRequest request) 36 | { 37 | var conversionResult = await ConvertRequestToCloudEvent(request); 38 | 39 | await PublishEventAsync(conversionResult.Event); 40 | 41 | MeasureEventPublished(conversionResult.Event, conversionResult.KubernetesEvent); 42 | 43 | request.HttpContext.Response.Headers.TryAdd("X-Event-Id", conversionResult.Event.Id); 44 | return new OkResult(); 45 | } 46 | 47 | private async Task<(CloudEvent Event, KubernetesEventContext KubernetesEvent)> ConvertRequestToCloudEvent(HttpRequest request) 48 | { 49 | var payload = await request.ReadAsStringAsync(); 50 | _logger.LogInformation($"Kubernetes event received: {payload}"); 51 | 52 | var result = _cloudEventFactory.CreateFromRawKubernetesEvent(payload); 53 | return result; 54 | } 55 | 56 | private async Task PublishEventAsync(CloudEvent cloudEvent) 57 | { 58 | await _eventGridPublisher.PublishAsync(cloudEvent); 59 | } 60 | 61 | private void MeasureEventPublished(CloudEvent @event, KubernetesEventContext kubernetesEvent) 62 | { 63 | using (LogContext.PushProperty("Event-Kubernetes-Namespace", kubernetesEvent.Namespace)) 64 | using (LogContext.PushProperty("Event-Type", @event.Type)) 65 | { 66 | ILoggerExtensions.LogMetric(_logger, "Kubernetes Event Published", 1); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "storage1": { 4 | "type": "storage", 5 | "connectionId": "AzureWebJobsStorage" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "storage1": { 4 | "type": "storage.emulator", 5 | "connectionId": "AzureWebJobsStorage" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.Functions.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | using Arcus.EventGrid.Publishing; 6 | using Arcus.EventGrid.Publishing.Interfaces; 7 | using Kubernetes.EventGrid.Core.CloudEvents; 8 | using Kubernetes.EventGrid.Core.CloudEvents.Interfaces; 9 | using Kubernetes.EventGrid.Core.Kubernetes; 10 | using Kubernetes.EventGrid.Core.Kubernetes.Interfaces; 11 | using Newtonsoft.Json; 12 | using Newtonsoft.Json.Serialization; 13 | using Serilog; 14 | using Serilog.Configuration; 15 | using Serilog.Events; 16 | 17 | [assembly: FunctionsStartup(typeof(Kubernetes.EventGrid.Bridge.Host.Startup))] 18 | namespace Kubernetes.EventGrid.Bridge.Host 19 | { 20 | public class Startup : FunctionsStartup 21 | { 22 | public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder) 23 | { 24 | base.ConfigureAppConfiguration(builder); 25 | 26 | builder.ConfigurationBuilder.AddEnvironmentVariables("EventGridBridge_"); 27 | } 28 | 29 | public override void Configure(IFunctionsHostBuilder builder) 30 | { 31 | var configuration = GetConfiguration(builder); 32 | 33 | AddDependencies(builder, configuration); 34 | 35 | ConfigureSerialization(); 36 | ConfigureLogging(builder, configuration); 37 | } 38 | 39 | private void ConfigureSerialization() 40 | { 41 | JsonConvert.DefaultSettings = () => new JsonSerializerSettings 42 | { 43 | ContractResolver = new CamelCasePropertyNamesContractResolver() 44 | }; 45 | } 46 | 47 | private void AddDependencies(IFunctionsHostBuilder builder, IConfiguration configuration) 48 | { 49 | builder.Services.AddTransient(); 50 | builder.Services.AddTransient(); 51 | builder.Services.AddTransient(); 52 | 53 | AddEventGridPublisher(builder, configuration); 54 | } 55 | 56 | private static void AddEventGridPublisher(IFunctionsHostBuilder builder, IConfiguration configuration) 57 | { 58 | var topicEndpoint = configuration["EventGrid_Topic_Uri"]; 59 | var topicKey = configuration["EventGrid_Topic_Key"]; 60 | 61 | var eventGridPublisher = EventGridPublisherBuilder 62 | .ForTopic(topicEndpoint) 63 | .UsingAuthenticationKey(topicKey) 64 | .Build(); 65 | 66 | builder.Services.AddTransient(provider => eventGridPublisher); 67 | } 68 | 69 | private static void ConfigureLogging(IFunctionsHostBuilder builder, IConfiguration configuration) 70 | { 71 | var dependencyContainer = builder.Services.BuildServiceProvider(); 72 | var kubernetesInfoProvider = dependencyContainer.GetRequiredService(); 73 | var clusterName = kubernetesInfoProvider.GetClusterName(); 74 | 75 | var instrumentationKey = configuration.GetValue("APPINSIGHTS_INSTRUMENTATIONKEY"); 76 | 77 | var loggerConfiguration = new LoggerConfiguration() 78 | .MinimumLevel.Debug() 79 | .MinimumLevel.Override("Microsoft", LogEventLevel.Information) 80 | .Enrich.FromLogContext() 81 | .Enrich.WithComponentName("Kubernetes Event Grid Bridge") 82 | .Enrich.WithProperty("Kubernetes-Cluster-Name", clusterName) 83 | .Enrich.WithKubernetesInfo() 84 | .Enrich.WithVersion() 85 | .WriteTo.Console(); 86 | 87 | if (string.IsNullOrWhiteSpace(instrumentationKey) == false) 88 | { 89 | loggerConfiguration = loggerConfiguration.WriteTo.AzureApplicationInsights(instrumentationKey); 90 | } 91 | 92 | var logger = loggerConfiguration.CreateLogger(); 93 | 94 | builder.Services.AddLogging(loggingBuilder => 95 | { 96 | loggingBuilder.ClearProvidersExceptFunctionProviders(); 97 | loggingBuilder.AddSerilog(logger); 98 | }); 99 | } 100 | 101 | private static IConfiguration GetConfiguration(IFunctionsHostBuilder builder) 102 | { 103 | var serviceProvider = builder.Services.BuildServiceProvider(); 104 | var configuration = serviceProvider.GetRequiredService(); 105 | return configuration; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.Host/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingExcludedTypes": "Request", 6 | "samplingSettings": { 7 | "isEnabled": true 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30225.117 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D3C4EA61-D045-4C96-8C53-2B5DE90315BC}" 7 | ProjectSection(SolutionItems) = preProject 8 | Kubernetes.EventGrid.Bridge.sln.DotSettings = Kubernetes.EventGrid.Bridge.sln.DotSettings 9 | EndProjectSection 10 | EndProject 11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kubernetes.EventGrid.Bridge.Host", "Kubernetes.EventGrid.Bridge.Host\Kubernetes.EventGrid.Bridge.Host.csproj", "{A9EDC108-4D16-4360-B563-6CBA88C36A5B}" 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Events", "Events", "{487C0A64-1543-40B1-A6C7-6025B0CFD6B8}" 14 | EndProject 15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kubernetes.EventGrid.Core", "Kubernetes.EventGrid.Core\Kubernetes.EventGrid.Core.csproj", "{10DD3A89-C475-495B-913B-04A1DF4DC297}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kubernetes.EventGrid.Tests.Unit", "Kubernetes.EventGrid.Tests.Unit\Kubernetes.EventGrid.Tests.Unit.csproj", "{BD4B9825-A792-46B8-A2DD-AF6BA949B527}" 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "KEDA", "KEDA", "{3C176301-E2A4-49C0-8DF2-C2E5B5ABF453}" 20 | ProjectSection(SolutionItems) = preProject 21 | ..\events\KEDA\KEDAScalerFailed.json = ..\events\KEDA\KEDAScalerFailed.json 22 | ..\events\KEDA\KEDAScalersStarted.json = ..\events\KEDA\KEDAScalersStarted.json 23 | ..\events\KEDA\KEDAScaleTargetActivated.json = ..\events\KEDA\KEDAScaleTargetActivated.json 24 | ..\events\KEDA\KEDAScaleTargetDeactivated.json = ..\events\KEDA\KEDAScaleTargetDeactivated.json 25 | ..\events\KEDA\ScaledObjectReady.json = ..\events\KEDA\ScaledObjectReady.json 26 | EndProjectSection 27 | EndProject 28 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{AB7921A0-4BF3-44DC-B443-7A272EAAC25C}" 29 | ProjectSection(SolutionItems) = preProject 30 | ..\events\core\ContainerStarted.json = ..\events\core\ContainerStarted.json 31 | ..\events\core\FailedCreatePodSandBox.json = ..\events\core\FailedCreatePodSandBox.json 32 | ..\events\core\ImagePulled.json = ..\events\core\ImagePulled.json 33 | ..\events\core\InvalidDiskCapacity.json = ..\events\core\InvalidDiskCapacity.json 34 | ..\events\core\KillingContainer.json = ..\events\core\KillingContainer.json 35 | ..\events\core\KillingPod.json = ..\events\core\KillingPod.json 36 | ..\events\core\NodeAllocatableEnforced.json = ..\events\core\NodeAllocatableEnforced.json 37 | ..\events\core\NodeHasNoDiskPressure.json = ..\events\core\NodeHasNoDiskPressure.json 38 | ..\events\core\NodeHasSufficientMemory.json = ..\events\core\NodeHasSufficientMemory.json 39 | ..\events\core\NodeHasSufficientPID.json = ..\events\core\NodeHasSufficientPID.json 40 | ..\events\core\NodeReady.json = ..\events\core\NodeReady.json 41 | ..\events\core\PodScheduled.json = ..\events\core\PodScheduled.json 42 | ..\events\core\PodUnhealthyDueToHealthProbe.json = ..\events\core\PodUnhealthyDueToHealthProbe.json 43 | ..\events\core\PodUnhealthyDueToReadinessProbe.json = ..\events\core\PodUnhealthyDueToReadinessProbe.json 44 | ..\events\core\PodVolumeMountFailed.json = ..\events\core\PodVolumeMountFailed.json 45 | ..\events\core\PullingImage.json = ..\events\core\PullingImage.json 46 | ..\events\core\RegisteredNode.json = ..\events\core\RegisteredNode.json 47 | ..\events\core\RemovingNode.json = ..\events\core\RemovingNode.json 48 | ..\events\core\ScalingReplicaSetDown.json = ..\events\core\ScalingReplicaSetDown.json 49 | ..\events\core\ScalingReplicaSetUp.json = ..\events\core\ScalingReplicaSetUp.json 50 | ..\events\core\StartingKubelet.json = ..\events\core\StartingKubelet.json 51 | ..\events\core\SuccesfulCreate.json = ..\events\core\SuccesfulCreate.json 52 | ..\events\core\SuccessfulDelete.json = ..\events\core\SuccessfulDelete.json 53 | ..\events\core\UpdatedLoadBalancer.json = ..\events\core\UpdatedLoadBalancer.json 54 | EndProjectSection 55 | EndProject 56 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cluster-Autoscaler", "Cluster-Autoscaler", "{71B586CB-8BC9-44EB-A2E0-A07F468BBDD2}" 57 | ProjectSection(SolutionItems) = preProject 58 | ..\events\cluster-autoscaler\NotTriggerScaleUp.json = ..\events\cluster-autoscaler\NotTriggerScaleUp.json 59 | ..\events\cluster-autoscaler\ScaleDown.json = ..\events\cluster-autoscaler\ScaleDown.json 60 | ..\events\cluster-autoscaler\ScaleDownEmpty.json = ..\events\cluster-autoscaler\ScaleDownEmpty.json 61 | ..\events\cluster-autoscaler\ScaledUpGroup.json = ..\events\cluster-autoscaler\ScaledUpGroup.json 62 | ..\events\cluster-autoscaler\TriggeredScaleUp.json = ..\events\cluster-autoscaler\TriggeredScaleUp.json 63 | EndProjectSection 64 | EndProject 65 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kubernetes.EventGrid.Bridge.Contracts", "Kubernetes.EventGrid.Bridge.Contracts\Kubernetes.EventGrid.Bridge.Contracts.csproj", "{C85F9E3A-DC65-4242-B734-BA9DDBEBC6CA}" 66 | EndProject 67 | Global 68 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 69 | Debug|Any CPU = Debug|Any CPU 70 | Release|Any CPU = Release|Any CPU 71 | EndGlobalSection 72 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 73 | {A9EDC108-4D16-4360-B563-6CBA88C36A5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 74 | {A9EDC108-4D16-4360-B563-6CBA88C36A5B}.Debug|Any CPU.Build.0 = Debug|Any CPU 75 | {A9EDC108-4D16-4360-B563-6CBA88C36A5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 76 | {A9EDC108-4D16-4360-B563-6CBA88C36A5B}.Release|Any CPU.Build.0 = Release|Any CPU 77 | {10DD3A89-C475-495B-913B-04A1DF4DC297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 78 | {10DD3A89-C475-495B-913B-04A1DF4DC297}.Debug|Any CPU.Build.0 = Debug|Any CPU 79 | {10DD3A89-C475-495B-913B-04A1DF4DC297}.Release|Any CPU.ActiveCfg = Release|Any CPU 80 | {10DD3A89-C475-495B-913B-04A1DF4DC297}.Release|Any CPU.Build.0 = Release|Any CPU 81 | {BD4B9825-A792-46B8-A2DD-AF6BA949B527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 82 | {BD4B9825-A792-46B8-A2DD-AF6BA949B527}.Debug|Any CPU.Build.0 = Debug|Any CPU 83 | {BD4B9825-A792-46B8-A2DD-AF6BA949B527}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {BD4B9825-A792-46B8-A2DD-AF6BA949B527}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {C85F9E3A-DC65-4242-B734-BA9DDBEBC6CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 86 | {C85F9E3A-DC65-4242-B734-BA9DDBEBC6CA}.Debug|Any CPU.Build.0 = Debug|Any CPU 87 | {C85F9E3A-DC65-4242-B734-BA9DDBEBC6CA}.Release|Any CPU.ActiveCfg = Release|Any CPU 88 | {C85F9E3A-DC65-4242-B734-BA9DDBEBC6CA}.Release|Any CPU.Build.0 = Release|Any CPU 89 | EndGlobalSection 90 | GlobalSection(SolutionProperties) = preSolution 91 | HideSolutionNode = FALSE 92 | EndGlobalSection 93 | GlobalSection(NestedProjects) = preSolution 94 | {3C176301-E2A4-49C0-8DF2-C2E5B5ABF453} = {487C0A64-1543-40B1-A6C7-6025B0CFD6B8} 95 | {AB7921A0-4BF3-44DC-B443-7A272EAAC25C} = {487C0A64-1543-40B1-A6C7-6025B0CFD6B8} 96 | {71B586CB-8BC9-44EB-A2E0-A07F468BBDD2} = {487C0A64-1543-40B1-A6C7-6025B0CFD6B8} 97 | EndGlobalSection 98 | GlobalSection(ExtensibilityGlobals) = postSolution 99 | SolutionGuid = {3D5F6D13-33B8-4464-887A-2361225667A4} 100 | EndGlobalSection 101 | EndGlobal 102 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Bridge.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | SUGGESTION 3 | SUGGESTION 4 | SUGGESTION 5 | SUGGESTION 6 | SUGGESTION 7 | SUGGESTION 8 | False 9 | NEVER 10 | True 11 | LINE_BREAK 12 | LINE_BREAK 13 | CHOP_IF_LONG 14 | CHOP_ALWAYS 15 | None 16 | False 17 | <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> 18 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 19 | True 20 | True 21 | True 22 | True 23 | True 24 | True 25 | True 26 | True 27 | True 28 | True 29 | True -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/CloudEvents/CloudEventFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Mime; 3 | using CloudNative.CloudEvents; 4 | using GuardNet; 5 | using Kubernetes.EventGrid.Bridge.Contracts.Extensions; 6 | using Kubernetes.EventGrid.Core.CloudEvents.Interfaces; 7 | using Kubernetes.EventGrid.Core.Kubernetes; 8 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 9 | using Kubernetes.EventGrid.Core.Kubernetes.Interfaces; 10 | 11 | namespace Kubernetes.EventGrid.Core.CloudEvents 12 | { 13 | public class CloudEventFactory : ICloudEventFactory 14 | { 15 | private readonly IKubernetesEventParser _kubernetesEventParser; 16 | private readonly IKubernetesClusterInfoProvider _kubernetesClusterInfoProvider; 17 | 18 | /// 19 | /// Constructor 20 | /// 21 | /// Converter to convert raw Kubernetes events into user-friendly events 22 | /// Provider for getting Kubernetes cluster information 23 | public CloudEventFactory(IKubernetesEventParser kubernetesEventParser, IKubernetesClusterInfoProvider kubernetesClusterInfoProvider) 24 | { 25 | Guard.NotNull(kubernetesClusterInfoProvider, nameof(kubernetesClusterInfoProvider)); 26 | Guard.NotNull(kubernetesClusterInfoProvider, nameof(kubernetesClusterInfoProvider)); 27 | 28 | _kubernetesEventParser = kubernetesEventParser; 29 | _kubernetesClusterInfoProvider = kubernetesClusterInfoProvider; 30 | } 31 | 32 | /// 33 | /// Creates a CloudEvent for a raw Kubernetes event 34 | /// 35 | /// Raw Kubernetes event 36 | public virtual (CloudEvent Event, KubernetesEventContext KubernetesEventContext) CreateFromRawKubernetesEvent(string payload) 37 | { 38 | var kubernetesEvent = _kubernetesEventParser.ParseFromRawNativeEvent(payload); 39 | 40 | var eventType = kubernetesEvent.Type.GetDescription(); 41 | var source = kubernetesEvent.Source ?? new Uri("http://kubernetes"); 42 | var subject = ComposeEventSubject(kubernetesEvent); 43 | var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0, eventType, source, subject: subject) 44 | { 45 | DataContentType = new ContentType("application/json"), 46 | Data = kubernetesEvent.Payload 47 | }; 48 | 49 | return (cloudEvent, new KubernetesEventContext(kubernetesEvent.Namespace)); 50 | } 51 | 52 | private string ComposeEventSubject(IKubernetesEvent kubernetesEvent) 53 | { 54 | var clusterName = _kubernetesClusterInfoProvider.GetClusterName(); 55 | var subject = kubernetesEvent.Subject ?? string.Empty; 56 | 57 | // Remove leading /, if present 58 | if (subject.StartsWith("/")) 59 | { 60 | subject = subject.Remove(0, 1); 61 | } 62 | 63 | // Always suffix with cluster name 64 | return $"/{clusterName}/{subject}"; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/CloudEvents/Interfaces/ICloudEventFactory.cs: -------------------------------------------------------------------------------- 1 | using CloudNative.CloudEvents; 2 | using Kubernetes.EventGrid.Core.Kubernetes; 3 | 4 | namespace Kubernetes.EventGrid.Core.CloudEvents.Interfaces 5 | { 6 | public interface ICloudEventFactory 7 | { 8 | /// 9 | /// Creates a CloudEvent for a raw Kubernetes event 10 | /// 11 | /// Raw Kubernetes event 12 | (CloudEvent Event, KubernetesEventContext KubernetesEventContext) CreateFromRawKubernetesEvent(string payload); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes.EventGrid.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Converters/ClusterAutoscalerEventConverter.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler; 3 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 4 | using Kubernetes.EventGrid.Core.Kubernetes.Parsers; 5 | using Newtonsoft.Json.Linq; 6 | 7 | namespace Kubernetes.EventGrid.Core.Kubernetes.Converters 8 | { 9 | public class ClusterAutoscalerEventConverter : EventConverter, IEventConverter 10 | { 11 | private const string EventSource = "http://kubernetes/autoscaling/cluster-autoscaler"; 12 | 13 | public IKubernetesEvent ConvertFromNativeEvent(JToken parsedPayload) 14 | { 15 | var eventReason = parsedPayload["reason"]?.ToString()?.ToLower(); 16 | switch (eventReason) 17 | { 18 | // TODO: Cluster node group is at max capacity 19 | // case "nottriggerscaleup": 20 | case "triggeredscaleup": 21 | return ConvertClusterScalingOut(parsedPayload); 22 | default: 23 | return ComposeRawKubernetesEvent(parsedPayload); 24 | } 25 | } 26 | 27 | private IKubernetesEvent ConvertClusterScalingOut(JToken parsedPayload) 28 | { 29 | var nodeGroupResizeInformation = ClusterAutoscalerEventParser.ParseForClusterScalingOut(parsedPayload["message"]?.ToString()); 30 | var scaleOutPayload = new ClusterAutoscalerScaleEventPayload 31 | { 32 | NodeGroup = nodeGroupResizeInformation 33 | }; 34 | 35 | return CreateKubernetesEvent(KubernetesEventType.ClusterAutoscalerScaleOut, EventSource, $"/node-groups/{nodeGroupResizeInformation.Name}", scaleOutPayload, parsedPayload); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Converters/DeploymentControllerEventConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 3 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 4 | using Kubernetes.EventGrid.Core.Kubernetes.Parsers; 5 | using Newtonsoft.Json.Linq; 6 | 7 | namespace Kubernetes.EventGrid.Core.Kubernetes.Converters 8 | { 9 | public class DeploymentControllerEventConverter : EventConverter, IEventConverter 10 | { 11 | private const string EventSource = "http://kubernetes/core/controllers/deployment"; 12 | 13 | public IKubernetesEvent ConvertFromNativeEvent(JToken parsedPayload) 14 | { 15 | var eventReason = parsedPayload["reason"]?.ToString()?.ToLower(); 16 | switch (eventReason) 17 | { 18 | case "scalingreplicaset": 19 | return ConvertScalingReplicaSet(parsedPayload); 20 | default: 21 | return ComposeRawKubernetesEvent(parsedPayload); 22 | } 23 | } 24 | 25 | private IKubernetesEvent ConvertScalingReplicaSet(JToken parsedPayload) 26 | { 27 | var parsingResult = DeploymentControllerEventParser.ParseForScalingReplicaSet(parsedPayload); 28 | 29 | KubernetesEventType eventType; 30 | switch (parsingResult.ScaleDirection) 31 | { 32 | case HorizontalScaleDirection.In: 33 | eventType = KubernetesEventType.DeploymentScaleIn; 34 | break; 35 | case HorizontalScaleDirection.Out: 36 | eventType = KubernetesEventType.DeploymentScaleOut; 37 | break; 38 | default: 39 | throw new ArgumentOutOfRangeException(nameof(parsingResult.ScaleDirection), parsingResult.ScaleDirection, "Unable to determine event type for scale direction"); 40 | } 41 | 42 | return CreateKubernetesEvent(eventType, EventSource, $"/namespaces/{parsingResult.Payload.Deployment.Namespace}/deployments/{parsingResult.Payload.Deployment.Name}", parsingResult.Payload, parsedPayload); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Converters/EventConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 3 | using Kubernetes.EventGrid.Core.Kubernetes.Events; 4 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 5 | using Newtonsoft.Json.Linq; 6 | 7 | namespace Kubernetes.EventGrid.Core.Kubernetes.Converters 8 | { 9 | public abstract class EventConverter 10 | { 11 | protected string GetKubernetesNamespaceThatEmittedEvent(JToken parsedPayload) 12 | { 13 | return parsedPayload["metadata"]?["namespace"]?.ToString(); 14 | } 15 | 16 | protected IKubernetesEvent ComposeRawKubernetesEvent(JToken parsedPayload) 17 | { 18 | var @namespace = GetKubernetesNamespaceThatEmittedEvent(parsedPayload); 19 | return new KubernetesEvent(KubernetesEventType.Raw, parsedPayload.ToObject(), @namespace); 20 | } 21 | 22 | protected KubernetesEvent CreateKubernetesEvent(KubernetesEventType eventType, string source, string subject, object payload, JToken parsedPayload) 23 | { 24 | var @namespace = GetKubernetesNamespaceThatEmittedEvent(parsedPayload); 25 | 26 | return new KubernetesEvent(eventType, payload, @namespace) 27 | { 28 | Source = new Uri(source), 29 | Subject = subject 30 | }; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Converters/IEventConverter.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 2 | using Newtonsoft.Json.Linq; 3 | 4 | namespace Kubernetes.EventGrid.Core.Kubernetes.Converters 5 | { 6 | public interface IEventConverter 7 | { 8 | IKubernetesEvent ConvertFromNativeEvent(JToken parsedPayload); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Events/Interfaces/IKubernetesEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 3 | 4 | namespace Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces 5 | { 6 | public interface IKubernetesEvent 7 | { 8 | public KubernetesEventType Type { get; } 9 | public object Payload { get; } 10 | public Uri? Source { get; } 11 | public string Subject { get; } 12 | 13 | /// 14 | /// Namespace from which it was emitted 15 | /// 16 | public string Namespace { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Events/KubernetesEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GuardNet; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 4 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 5 | 6 | namespace Kubernetes.EventGrid.Core.Kubernetes.Events 7 | { 8 | public class KubernetesEvent : IKubernetesEvent 9 | { 10 | public KubernetesEvent(KubernetesEventType eventType, object payload, string @namespace) 11 | { 12 | Guard.For(() => eventType == KubernetesEventType.Unspecified, "No event type was provided"); 13 | Guard.NotNull(nameof(payload), nameof(payload)); 14 | 15 | Type = eventType; 16 | Payload = payload; 17 | Namespace = string.IsNullOrWhiteSpace(@namespace) ? "unknown" : @namespace; 18 | } 19 | 20 | public KubernetesEventType Type { get; } 21 | public object Payload { get; set; } 22 | public Uri? Source { get; set; } 23 | public string Subject { get; set; } 24 | 25 | /// 26 | /// Namespace from which it was emitted 27 | /// 28 | public string Namespace { get; set; } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Interfaces/IKubernetesClusterInfoProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Kubernetes.EventGrid.Core.Kubernetes.Interfaces 2 | { 3 | public interface IKubernetesClusterInfoProvider 4 | { 5 | string GetClusterName(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Interfaces/IKubernetesEventParser.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 2 | 3 | namespace Kubernetes.EventGrid.Core.Kubernetes.Interfaces 4 | { 5 | public interface IKubernetesEventParser 6 | { 7 | /// 8 | /// Parses a raw Kubernetes native event into user-friendly events 9 | /// 10 | /// Raw payload containing the native Kubernetes event 11 | /// User-friendly Kubernetes event 12 | public IKubernetesEvent ParseFromRawNativeEvent(string rawPayload); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/KubernetesClusterInfoProvider.cs: -------------------------------------------------------------------------------- 1 | using GuardNet; 2 | using Kubernetes.EventGrid.Core.Kubernetes.Interfaces; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace Kubernetes.EventGrid.Core.Kubernetes 6 | { 7 | public class KubernetesClusterInfoProvider : IKubernetesClusterInfoProvider 8 | { 9 | public const string DefaultClusterName = "unknown-cluster"; 10 | private readonly IConfiguration _configuration; 11 | 12 | public KubernetesClusterInfoProvider(IConfiguration configuration) 13 | { 14 | Guard.NotNull(configuration, nameof(configuration)); 15 | 16 | _configuration = configuration; 17 | } 18 | 19 | public string GetClusterName() 20 | { 21 | var configuredClusterName = _configuration.GetValue("Kubernetes_Cluster_Name"); 22 | 23 | if (string.IsNullOrWhiteSpace(configuredClusterName)) 24 | { 25 | return DefaultClusterName; 26 | } 27 | 28 | return configuredClusterName; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/KubernetesEventContext.cs: -------------------------------------------------------------------------------- 1 | using GuardNet; 2 | 3 | namespace Kubernetes.EventGrid.Core.Kubernetes 4 | { 5 | public class KubernetesEventContext 6 | { 7 | public string Namespace { get; } 8 | 9 | public KubernetesEventContext(string @namespace) 10 | { 11 | Guard.NotNullOrWhitespace(@namespace, nameof(@namespace)); 12 | 13 | Namespace = @namespace; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/KubernetesEventParser.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Core.Kubernetes.Converters; 2 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 3 | using Kubernetes.EventGrid.Core.Kubernetes.Interfaces; 4 | using Newtonsoft.Json.Linq; 5 | 6 | namespace Kubernetes.EventGrid.Core.Kubernetes 7 | { 8 | public class KubernetesEventParser : EventConverter, IKubernetesEventParser 9 | { 10 | /// 11 | /// Parses a raw Kubernetes native event into user-friendly events 12 | /// 13 | /// Raw payload containing the native Kubernetes event 14 | /// User-friendly Kubernetes event 15 | public virtual IKubernetesEvent ParseFromRawNativeEvent(string rawPayload) 16 | { 17 | var parsedPayload = JToken.Parse(rawPayload); 18 | 19 | var sourceComponent = parsedPayload["source"]?["component"]?.ToString()?.ToLower(); 20 | switch (sourceComponent) 21 | { 22 | case "deployment-controller": 23 | var deploymentController = new DeploymentControllerEventConverter(); 24 | return deploymentController.ConvertFromNativeEvent(parsedPayload); 25 | case "cluster-autoscaler": 26 | var clusterAutoscalerEventConverter = new ClusterAutoscalerEventConverter(); 27 | return clusterAutoscalerEventConverter.ConvertFromNativeEvent(parsedPayload); 28 | default: 29 | return ComposeRawKubernetesEvent(parsedPayload); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Parsers/ClusterAutoscalerEventParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler; 4 | 5 | namespace Kubernetes.EventGrid.Core.Kubernetes.Parsers 6 | { 7 | public static class ClusterAutoscalerEventParser 8 | { 9 | /// 10 | /// Regex to parse the cluster resize information 11 | /// 12 | /// pod triggered scale-up: [{aks-agentpool-11593772-vmss 1->2 (max: 2)}] 13 | private const string ClusterResizeRegex = @"\[\{([^\s]+) ([0-9]*)->([0-9]*) \(max: ([0-9]*)"; 14 | 15 | public static NodeGroupResizeInfo ParseForClusterScalingOut(string eventMessage) 16 | { 17 | if (Regex.IsMatch(eventMessage, ClusterResizeRegex) == false) 18 | { 19 | throw new ArgumentException("Provided input does not meet the needs to determine resized cluster info"); 20 | } 21 | 22 | var matchingEntries = Regex.Match(eventMessage, ClusterResizeRegex); 23 | 24 | var nodeGroupName = matchingEntries.Groups[1].Value; 25 | var newSizeInfo = new NewNodeGroupSizeInfo 26 | { 27 | New = int.Parse(matchingEntries.Groups[3].Value), 28 | Old = int.Parse(matchingEntries.Groups[2].Value), 29 | Maximum = int.Parse(matchingEntries.Groups[4].Value) 30 | }; 31 | 32 | var nodeGroupResizeInfo = new NodeGroupResizeInfo 33 | { 34 | Name = nodeGroupName, 35 | SizeInfo = newSizeInfo 36 | }; 37 | 38 | return nodeGroupResizeInfo; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Core/Kubernetes/Parsers/DeploymentControllerEventParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.RegularExpressions; 4 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 5 | using Kubernetes.EventGrid.Bridge.Contracts.Events.Deployments; 6 | using Newtonsoft.Json.Linq; 7 | 8 | namespace Kubernetes.EventGrid.Core.Kubernetes.Parsers 9 | { 10 | public class DeploymentControllerEventParser 11 | { 12 | /// 13 | /// Regex to parse the message to get scaling information 14 | /// 15 | /// Scaled up replica set k8s-event-grid-bridge-workload-76888d9cc9 to 1 16 | private const string MessageRegex = @"Scaled ([^\s]+) replica set ([^\s]+) to ([0-9]*)"; 17 | 18 | public static (HorizontalScaleDirection ScaleDirection, DeploymentScaleEventPayload Payload) ParseForScalingReplicaSet(JToken @event) 19 | { 20 | var deploymentInfoToken = @event["involvedObject"]; 21 | if (deploymentInfoToken == null || deploymentInfoToken["kind"]?.ToString()?.Equals("Deployment", StringComparison.InvariantCultureIgnoreCase) == false) 22 | { 23 | throw new Exception("No deployment info was found in 'involvedObject'"); 24 | } 25 | 26 | // Interpret message to get more detailed information 27 | var eventMessage = @event["message"]?.ToString(); 28 | if (Regex.IsMatch(eventMessage, MessageRegex) == false) 29 | { 30 | throw new ArgumentException("Provided input does not meet the needs to determine resized cluster info"); 31 | } 32 | 33 | var matchingEntries = Regex.Match(eventMessage, MessageRegex); 34 | 35 | var payload = ComposePayload(deploymentInfoToken, matchingEntries); 36 | var scaleDirection = DetermineScaleDirection(matchingEntries); 37 | 38 | return (scaleDirection, payload); 39 | } 40 | 41 | private static DeploymentScaleEventPayload ComposePayload(JToken deploymentInfoToken, Match matchingEntries) 42 | { 43 | var payload = new DeploymentScaleEventPayload 44 | { 45 | Deployment = new DeploymentInfo 46 | { 47 | Name = deploymentInfoToken["name"]?.ToString(), 48 | Namespace = deploymentInfoToken["namespace"]?.ToString(), 49 | }, 50 | ReplicaSet = new ReplicaSetInfo 51 | { 52 | Name = matchingEntries.Groups[2].Value 53 | }, 54 | Replicas = new ReplicaInfo 55 | { 56 | New = int.Parse(matchingEntries.Groups[3].Value) 57 | } 58 | }; 59 | 60 | var deploymentLabelToken = deploymentInfoToken["labels"]; 61 | if (deploymentLabelToken != null) 62 | { 63 | payload.Deployment.Labels = deploymentLabelToken.ToObject>(); 64 | } 65 | 66 | return payload; 67 | } 68 | 69 | private static HorizontalScaleDirection DetermineScaleDirection(Match regexMatchingEntries) 70 | { 71 | // Interpret regex results 72 | var rawScaleDirection = regexMatchingEntries.Groups[1].Value; 73 | 74 | HorizontalScaleDirection scaleDirection = HorizontalScaleDirection.NotSpecified; 75 | 76 | // Converting the raw scale direction from Kubernetes to our enum 77 | // See GitHub for more info: https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/deployment/sync.go#L342-L351 78 | if (rawScaleDirection.Equals("up", StringComparison.InvariantCultureIgnoreCase)) 79 | { 80 | scaleDirection = HorizontalScaleDirection.Out; 81 | } 82 | else if (rawScaleDirection.Equals("down", StringComparison.InvariantCultureIgnoreCase)) 83 | { 84 | scaleDirection = HorizontalScaleDirection.In; 85 | } 86 | 87 | return scaleDirection; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/CloudEvents/CloudEventFactoryUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Mime; 2 | using CloudNative.CloudEvents; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 4 | using Kubernetes.EventGrid.Bridge.Contracts.Extensions; 5 | using Kubernetes.EventGrid.Core.CloudEvents; 6 | using Kubernetes.EventGrid.Core.Kubernetes; 7 | using Kubernetes.EventGrid.Core.Kubernetes.Events; 8 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 9 | using Kubernetes.EventGrid.Core.Kubernetes.Interfaces; 10 | using Kubernetes.EventGrid.Tests.Unit.Events; 11 | using Moq; 12 | using Xunit; 13 | 14 | namespace Kubernetes.EventGrid.Tests.Unit.CloudEvents 15 | { 16 | public class CloudEventFactoryUnitTests : UnitTest 17 | { 18 | [Fact] 19 | public void ParseFromRawNativeEvent_ParseRawEvent_ReturnsRawEvent() 20 | { 21 | // Arrange 22 | var expectedContentType = new ContentType("application/json"); 23 | var expectedSource = "http://kubernetes/"; 24 | var rawKubernetesEvent = KubernetesEventSamples.GetRawContainerStartedEvent(); 25 | var kubernetesEvent = new KubernetesEvent(KubernetesEventType.Raw, rawKubernetesEvent, "default"); 26 | var mockedKubernetesEventParser = CreateMockedKubernetesEventParser(kubernetesEvent); 27 | var mockedKubernetesClusterInfoProvider = new Mock(); 28 | var cloudEventFactory = new CloudEventFactory(mockedKubernetesEventParser.Object, mockedKubernetesClusterInfoProvider.Object); 29 | 30 | // Act 31 | var conversionResult = cloudEventFactory.CreateFromRawKubernetesEvent(rawKubernetesEvent); 32 | 33 | // Assert 34 | var cloudEvent = conversionResult.Event; 35 | Assert.NotNull(cloudEvent); 36 | Assert.Equal(kubernetesEvent.Type.GetDescription(), cloudEvent.Type); 37 | Assert.Equal(kubernetesEvent.Payload, cloudEvent.Data); 38 | Assert.Equal(expectedContentType, cloudEvent.DataContentType); 39 | Assert.NotNull(cloudEvent.Source); 40 | Assert.Equal(expectedSource, cloudEvent.Source.AbsoluteUri); 41 | Assert.Equal(CloudEventsSpecVersion.V1_0, cloudEvent.SpecVersion); 42 | mockedKubernetesEventParser.Verify(parser=>parser.ParseFromRawNativeEvent(It.IsAny()), Times.Once); 43 | } 44 | 45 | private static Mock CreateMockedKubernetesEventParser(IKubernetesEvent kubernetesEvent) 46 | { 47 | var mockedKubernetesEventParser = new Mock(); 48 | mockedKubernetesEventParser.Setup(parser => parser.ParseFromRawNativeEvent(It.IsAny())) 49 | .Returns(kubernetesEvent); 50 | 51 | return mockedKubernetesEventParser; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Events/KubernetesEventSamples.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Kubernetes.EventGrid.Tests.Unit.Events 4 | { 5 | public static class KubernetesEventSamples 6 | { 7 | public static string GetRawContainerStartedEvent() 8 | { 9 | return ReadEventFromDisk("Core", "ContainerStarted.json"); 10 | } 11 | 12 | public static string GetRawClusterAutoscalerScaleOutEvent() 13 | { 14 | return ReadEventFromDisk("Cluster-Autoscaler", "TriggeredScaleUp.json"); 15 | } 16 | 17 | public static string GetRawReplicaSetScaleInEvent() 18 | { 19 | return ReadEventFromDisk("Core", "ScalingReplicaSetDown.json"); 20 | } 21 | 22 | public static string GetRawReplicaSetScaleOutEvent() 23 | { 24 | return ReadEventFromDisk("Core", "ScalingReplicaSetUp.json"); 25 | } 26 | 27 | private static string ReadEventFromDisk(string folderName, string fileName) 28 | { 29 | var filePath = Path.Combine("Events", "Samples", folderName, fileName); 30 | return File.ReadAllText(filePath); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Extensions/EnumExtensionsUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Extensions; 3 | using Kubernetes.EventGrid.Tests.Unit.Extensions.Enums; 4 | using Xunit; 5 | 6 | namespace Kubernetes.EventGrid.Tests.Unit.Extensions 7 | { 8 | public class EnumExtensionsUnitTests : UnitTest 9 | { 10 | [Fact] 11 | public void GetDescription_ValueHasDescription_DescriptionIsReturned() 12 | { 13 | // Arrange 14 | const string expectedValue = "Kubernetes.Events.Raw"; 15 | var enumValue = KubernetesEventType.Raw; 16 | 17 | // Act 18 | var enumDescription = enumValue.GetDescription(); 19 | 20 | // Assert 21 | Assert.Equal(expectedValue, enumDescription); 22 | } 23 | 24 | [Fact] 25 | public void GetDescription_ValueHasNoDescriptionAndNoDefaultSpecified_EnumValueIsReturned() 26 | { 27 | // Arrange 28 | const string expectedValue = "OptionTwo"; 29 | var enumValue = ExampleEnum.OptionTwo; 30 | 31 | // Act 32 | var enumDescription = enumValue.GetDescription(); 33 | 34 | // Assert 35 | Assert.Equal(expectedValue, enumDescription); 36 | } 37 | 38 | [Fact] 39 | public void GetDescription_ValueHasNoDescriptionAndHasDefaultSpecified_DefaultIsReturned() 40 | { 41 | // Arrange 42 | const string expectedValue = "DefaultOption"; 43 | var enumValue = ExampleEnum.OptionTwo; 44 | 45 | // Act 46 | var enumDescription = enumValue.GetDescription(defaultDescription: expectedValue); 47 | 48 | // Assert 49 | Assert.Equal(expectedValue, enumDescription); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Extensions/Enums/ExampleEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Kubernetes.EventGrid.Tests.Unit.Extensions.Enums 2 | { 3 | public enum ExampleEnum 4 | { 5 | OptionOne, 6 | OptionTwo 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes.EventGrid.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | true 6 | 7 | 8 | 9 | 1701;1702;1591 10 | 11 | 12 | 13 | 1701;1702;1591 14 | 15 | 16 | 17 | 18 | Always 19 | 20 | 21 | Always 22 | 23 | 24 | Always 25 | 26 | 27 | Always 28 | 29 | 30 | Always 31 | 32 | 33 | Always 34 | 35 | 36 | Always 37 | 38 | 39 | Always 40 | 41 | 42 | Always 43 | 44 | 45 | Always 46 | 47 | 48 | Always 49 | 50 | 51 | Always 52 | 53 | 54 | Always 55 | 56 | 57 | Always 58 | 59 | 60 | Always 61 | 62 | 63 | Always 64 | 65 | 66 | Always 67 | 68 | 69 | Always 70 | 71 | 72 | Always 73 | 74 | 75 | Always 76 | 77 | 78 | Always 79 | 80 | 81 | Always 82 | 83 | 84 | Always 85 | 86 | 87 | Always 88 | 89 | 90 | Always 91 | 92 | 93 | Always 94 | 95 | 96 | Always 97 | 98 | 99 | Always 100 | 101 | 102 | Always 103 | 104 | 105 | Always 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/ClusterAutoscaler/ClusterAutoscalerEventParserUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Core.Kubernetes.Parsers; 2 | using Xunit; 3 | 4 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes.ClusterAutoscaler 5 | { 6 | public class ClusterAutoscalerEventParserUnitTests : UnitTest 7 | { 8 | [Fact] 9 | public void ParseForClusterScalingOut_RawEventMessage_Succeeds() 10 | { 11 | // Arrange 12 | var expectedNodeGroupName = BogusGenerator.Name.FullName().Replace(" ", "-"); 13 | var oldNodeCount = BogusGenerator.Random.Int(100, 200); 14 | var newNodeCount = BogusGenerator.Random.Int(200, 300); 15 | var maximumNodeCount = BogusGenerator.Random.Int(300, 400); 16 | var eventMessage = $"pod triggered scale-up: [{{{expectedNodeGroupName} {oldNodeCount}->{newNodeCount} (max: {maximumNodeCount})}}]"; 17 | 18 | // Act 19 | var nodeGroupResizeInformation = ClusterAutoscalerEventParser.ParseForClusterScalingOut(eventMessage); 20 | 21 | // Assert 22 | Assert.NotNull(nodeGroupResizeInformation); 23 | Assert.NotNull(nodeGroupResizeInformation.SizeInfo); 24 | Assert.Equal(expectedNodeGroupName, nodeGroupResizeInformation.Name); 25 | Assert.Equal(oldNodeCount, nodeGroupResizeInformation.SizeInfo.Old); 26 | Assert.Equal(newNodeCount, nodeGroupResizeInformation.SizeInfo.New); 27 | Assert.Equal(maximumNodeCount, nodeGroupResizeInformation.SizeInfo.Maximum); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/Deployments/DeploymentControllerEventParserUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 2 | using Kubernetes.EventGrid.Core.Kubernetes.Parsers; 3 | using Kubernetes.EventGrid.Tests.Unit.Events; 4 | using Newtonsoft.Json.Linq; 5 | using Xunit; 6 | 7 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes.Deployments 8 | { 9 | public class DeploymentControllerEventParserUnitTests : DeploymentControllerEventParsingTests 10 | { 11 | [Fact] 12 | public void ParseForScalingReplicaSet_RawScaleOutEventMessage_Succeeds() 13 | { 14 | // Arrange 15 | var rawClusterAutoscalerScaleDownEvent = KubernetesEventSamples.GetRawReplicaSetScaleOutEvent(); 16 | var rawJToken = JToken.Parse(rawClusterAutoscalerScaleDownEvent); 17 | const HorizontalScaleDirection expectedScaleDirection = HorizontalScaleDirection.Out; 18 | 19 | // Act 20 | var parseOutcome = DeploymentControllerEventParser.ParseForScalingReplicaSet(rawJToken); 21 | 22 | // Assert 23 | AssertForExpectedDeploymentScalingPayload(expectedScaleDirection, parseOutcome.ScaleDirection, parseOutcome.Payload); 24 | } 25 | 26 | [Fact] 27 | public void ParseForScalingReplicaSet_RawScaleInEventMessage_Succeeds() 28 | { 29 | // Arrange 30 | var rawClusterAutoscalerScaleDownEvent = KubernetesEventSamples.GetRawReplicaSetScaleInEvent(); 31 | var rawJToken = JToken.Parse(rawClusterAutoscalerScaleDownEvent); 32 | const HorizontalScaleDirection expectedScaleDirection = HorizontalScaleDirection.In; 33 | 34 | // Act 35 | var parseOutcome = DeploymentControllerEventParser.ParseForScalingReplicaSet(rawJToken); 36 | 37 | // Assert 38 | AssertForExpectedDeploymentScalingPayload(expectedScaleDirection, parseOutcome.ScaleDirection, parseOutcome.Payload); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/Deployments/DeploymentControllerEventParsingTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 4 | using Kubernetes.EventGrid.Bridge.Contracts.Events.Deployments; 5 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 6 | using Xunit; 7 | 8 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes.Deployments 9 | { 10 | public class DeploymentControllerEventParsingTests : UnitTest 11 | { 12 | // Replicas 13 | protected const int ExpectedNewReplicaCountForScaleOut = 20; 14 | protected const int ExpectedNewReplicaCountForScaleIn = 10; 15 | 16 | // Deployment 17 | protected const string ExpectedDeploymentName = "k8s-event-grid-bridge-workload"; 18 | protected const string ExpectedDeploymentNamespace = "monitoring"; 19 | protected Dictionary ExpectedDeploymentLabels = new Dictionary 20 | { 21 | {"app", "k8s-event-grid-bridge"} 22 | }; 23 | 24 | // Replica Set 25 | protected const string ExpectedReplicaSetName = "k8s-event-grid-bridge-workload-76888d9cc9"; 26 | 27 | protected void AssertForExpectedDeploymentScalingEvent(KubernetesEventType expectedKubernetesEventType, IKubernetesEvent kubernetesEvent) 28 | { 29 | int expectedReplicaCount = expectedKubernetesEventType == KubernetesEventType.DeploymentScaleIn ? ExpectedNewReplicaCountForScaleIn : ExpectedNewReplicaCountForScaleOut; 30 | 31 | Assert.NotNull(kubernetesEvent); 32 | Assert.Equal(expectedKubernetesEventType, kubernetesEvent.Type); 33 | Assert.NotNull(kubernetesEvent.Payload); 34 | var deploymentScaleEventPayload = kubernetesEvent.Payload as DeploymentScaleEventPayload; 35 | AssertPayload(deploymentScaleEventPayload, expectedReplicaCount); 36 | } 37 | 38 | protected void AssertForExpectedDeploymentScalingPayload(HorizontalScaleDirection expectedScaleDirection, HorizontalScaleDirection scaleDirection, DeploymentScaleEventPayload deploymentScaleEventPayload) 39 | { 40 | int expectedReplicaCount = expectedScaleDirection == HorizontalScaleDirection.In ? ExpectedNewReplicaCountForScaleIn : ExpectedNewReplicaCountForScaleOut; 41 | 42 | Assert.Equal(expectedScaleDirection, scaleDirection); 43 | AssertPayload(deploymentScaleEventPayload, expectedReplicaCount); 44 | } 45 | 46 | private void AssertPayload(DeploymentScaleEventPayload deploymentScaleEventPayload, int expectedReplicaCount) 47 | { 48 | Assert.NotNull(deploymentScaleEventPayload); 49 | Assert.NotNull(deploymentScaleEventPayload.Deployment); 50 | Assert.NotNull(deploymentScaleEventPayload.Deployment.Labels); 51 | Assert.Equal(ExpectedDeploymentName, deploymentScaleEventPayload.Deployment.Name); 52 | Assert.Equal(ExpectedDeploymentNamespace, deploymentScaleEventPayload.Deployment.Namespace); 53 | Assert.Single(deploymentScaleEventPayload.Deployment.Labels); 54 | var deploymentLabel = deploymentScaleEventPayload.Deployment.Labels.First(); 55 | var expectedDeploymentLabel = ExpectedDeploymentLabels.First(); 56 | Assert.Equal(expectedDeploymentLabel.Key, deploymentLabel.Key); 57 | Assert.Equal(expectedDeploymentLabel.Value, deploymentLabel.Value); 58 | Assert.NotNull(deploymentScaleEventPayload.ReplicaSet); 59 | Assert.Equal(ExpectedReplicaSetName, deploymentScaleEventPayload.ReplicaSet.Name); 60 | Assert.NotNull(deploymentScaleEventPayload.Replicas); 61 | Assert.Equal(expectedReplicaCount, deploymentScaleEventPayload.Replicas.New); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/Deployments/KubernetesEventParserUnitTestsForDeployments.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler; 4 | using Kubernetes.EventGrid.Bridge.Contracts.Events.Deployments; 5 | using Kubernetes.EventGrid.Core.Kubernetes; 6 | using Kubernetes.EventGrid.Core.Kubernetes.Events.Interfaces; 7 | using Kubernetes.EventGrid.Tests.Unit.Events; 8 | using Xunit; 9 | 10 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes.Deployments 11 | { 12 | public class KubernetesEventParserUnitTestsForDeployments : DeploymentControllerEventParsingTests 13 | { 14 | [Fact] 15 | public void ParseFromRawNativeEvent_ParseRawReplicaSetScaleInEvent_ReturnsDeploymentScaleOutEvent() 16 | { 17 | // Arrange 18 | var kubernetesEventParser = new KubernetesEventParser(); 19 | var rawClusterAutoscalerScaleDownEvent = KubernetesEventSamples.GetRawReplicaSetScaleOutEvent(); 20 | 21 | // Act 22 | var kubernetesEvent = kubernetesEventParser.ParseFromRawNativeEvent(rawClusterAutoscalerScaleDownEvent); 23 | 24 | // Assert 25 | AssertForExpectedDeploymentScalingEvent(KubernetesEventType.DeploymentScaleOut, kubernetesEvent); 26 | } 27 | 28 | [Fact] 29 | public void ParseFromRawNativeEvent_ParseRawReplicaSetScaleInEvent_ReturnsDeploymentScaleInEvent() 30 | { 31 | // Arrange 32 | var kubernetesEventParser = new KubernetesEventParser(); 33 | var rawClusterAutoscalerScaleDownEvent = KubernetesEventSamples.GetRawReplicaSetScaleInEvent(); 34 | 35 | // Act 36 | var kubernetesEvent = kubernetesEventParser.ParseFromRawNativeEvent(rawClusterAutoscalerScaleDownEvent); 37 | 38 | // Assert 39 | AssertForExpectedDeploymentScalingEvent(KubernetesEventType.DeploymentScaleIn, kubernetesEvent); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/KubernetesClusterInfoProviderUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 3 | using Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler; 4 | using Kubernetes.EventGrid.Core.Kubernetes; 5 | using Kubernetes.EventGrid.Tests.Unit.Events; 6 | using Microsoft.Extensions.Configuration; 7 | using Xunit; 8 | 9 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes 10 | { 11 | public class KubernetesClusterInfoProviderUnitTests : UnitTest 12 | { 13 | [Fact] 14 | public void GetClusterName_NameIsConfigured_ReturnsConfiguredName() 15 | { 16 | // Arrange 17 | var expectedClusterName = BogusGenerator.Name.FullName(); 18 | var inMemoryConfiguration = new Dictionary 19 | { 20 | {"Kubernetes_Cluster_Name", expectedClusterName} 21 | }; 22 | var config = CreateInMemoryConfiguration(inMemoryConfiguration); 23 | var kubernetesClusterInfoProvider = new KubernetesClusterInfoProvider(config); 24 | 25 | // Act 26 | var clusterName = kubernetesClusterInfoProvider.GetClusterName(); 27 | 28 | // Assert 29 | Assert.Equal(expectedClusterName, clusterName); 30 | } 31 | 32 | [Fact] 33 | public void GetClusterName_NameIsNotConfigured_ReturnsDefaultName() 34 | { 35 | // Arrange 36 | var inMemoryConfiguration = new Dictionary(); 37 | var config = CreateInMemoryConfiguration(inMemoryConfiguration); 38 | var kubernetesClusterInfoProvider = new KubernetesClusterInfoProvider(config); 39 | 40 | // Act 41 | var clusterName = kubernetesClusterInfoProvider.GetClusterName(); 42 | 43 | // Assert 44 | Assert.Equal(KubernetesClusterInfoProvider.DefaultClusterName, clusterName); 45 | } 46 | 47 | private static IConfigurationRoot CreateInMemoryConfiguration(Dictionary inMemoryConfiguration) 48 | { 49 | var config = new ConfigurationBuilder() 50 | .AddInMemoryCollection(inMemoryConfiguration) 51 | .Build(); 52 | return config; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/Kubernetes/KubernetesEventParserUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Kubernetes.EventGrid.Bridge.Contracts.Enums; 2 | using Kubernetes.EventGrid.Bridge.Contracts.Events.ClusterAutoscaler; 3 | using Kubernetes.EventGrid.Core.Kubernetes; 4 | using Kubernetes.EventGrid.Tests.Unit.Events; 5 | using Xunit; 6 | 7 | namespace Kubernetes.EventGrid.Tests.Unit.Kubernetes 8 | { 9 | public class KubernetesEventParserUnitTests : UnitTest 10 | { 11 | [Fact] 12 | public void ParseFromRawNativeEvent_ParseRawEvent_ReturnsRawEvent() 13 | { 14 | // Arrange 15 | var kubernetesEventParser = new KubernetesEventParser(); 16 | var rawKubernetesEvent = KubernetesEventSamples.GetRawContainerStartedEvent(); 17 | 18 | // Act 19 | var kubernetesEvent = kubernetesEventParser.ParseFromRawNativeEvent(rawKubernetesEvent); 20 | 21 | // Assert 22 | Assert.NotNull(kubernetesEvent); 23 | Assert.Equal(KubernetesEventType.Raw, kubernetesEvent.Type); 24 | Assert.NotNull(kubernetesEvent.Payload); 25 | } 26 | 27 | [Fact] 28 | public void ParseFromRawNativeEvent_ParseRawClusterAutoscalerScaleInEvent_ReturnsClusterAutoscalerScaleInEvent() 29 | { 30 | // Arrange 31 | var kubernetesEventParser = new KubernetesEventParser(); 32 | var rawClusterAutoscalerScaleDownEvent = KubernetesEventSamples.GetRawClusterAutoscalerScaleOutEvent(); 33 | 34 | // Act 35 | var kubernetesEvent = kubernetesEventParser.ParseFromRawNativeEvent(rawClusterAutoscalerScaleDownEvent); 36 | 37 | // Assert 38 | Assert.NotNull(kubernetesEvent); 39 | Assert.Equal(KubernetesEventType.ClusterAutoscalerScaleOut, kubernetesEvent.Type); 40 | Assert.NotNull(kubernetesEvent.Payload); 41 | var clusterAutoscalerScaleEventPayload = kubernetesEvent.Payload as ClusterAutoscalerScaleEventPayload; 42 | Assert.NotNull(clusterAutoscalerScaleEventPayload); 43 | Assert.NotNull(clusterAutoscalerScaleEventPayload.NodeGroup); 44 | Assert.Equal("aks-agentpool-11593772-vmss", clusterAutoscalerScaleEventPayload.NodeGroup.Name); 45 | Assert.NotNull(clusterAutoscalerScaleEventPayload.NodeGroup.SizeInfo); 46 | Assert.Equal(1, clusterAutoscalerScaleEventPayload.NodeGroup.SizeInfo.Old); 47 | Assert.Equal(2, clusterAutoscalerScaleEventPayload.NodeGroup.SizeInfo.New); 48 | Assert.Equal(2, clusterAutoscalerScaleEventPayload.NodeGroup.SizeInfo.Maximum); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Kubernetes.EventGrid.Tests.Unit/UnitTest.cs: -------------------------------------------------------------------------------- 1 | using Bogus; 2 | using Xunit; 3 | 4 | namespace Kubernetes.EventGrid.Tests.Unit 5 | { 6 | [Trait("Category", "Unit")] 7 | public class UnitTest 8 | { 9 | protected Faker BogusGenerator { get; } = new Faker(); 10 | } 11 | } 12 | --------------------------------------------------------------------------------