Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cd944c9
Add deduplication, helper functions for wildcard path processing and …
hpyvovar-mycarrier Sep 16, 2025
a7c249f
Merge branch 'main' into deduplication-branch
smunukutla-mycarrier Sep 18, 2025
3deaee5
Refactor endpoint name processing to handle special cases and improve…
hpyvovar-mycarrier Oct 2, 2025
6d65d0f
Refactor endpoint name processing to use trimAll instead of trimSuffi…
hpyvovar-mycarrier Oct 2, 2025
85cb775
Refactor endpoint processing to use contains instead of hasSuffix for…
hpyvovar-mycarrier Oct 2, 2025
b45e0af
Update ArgoCD sync-options to use Force instead of PruneLast for depl…
smunukutla-mycarrier Sep 25, 2025
35f8f0f
Automated Change
smunukutla-mycarrier Sep 25, 2025
cbe0274
Add ServiceBusConnectionNamespace to environment variables in _lang.tpl
bcarlock-mycarrier Sep 25, 2025
3288653
Automated Change
bcarlock-mycarrier Sep 25, 2025
fdad4f5
Optimize performance by precomputing global context in templates and …
bcarlock-mycarrier Oct 2, 2025
fcd2978
Automated Change
bcarlock-mycarrier Oct 2, 2025
0ee105f
Remove subproject reference for MC.Truckload
hpyvovar-mycarrier Oct 9, 2025
cef7cfa
Implement endpoint deduplication logic and add comprehensive tests fo…
hpyvovar-mycarrier Oct 14, 2025
685c518
Add helper function for processing Istio VirtualService prefix paths
hpyvovar-mycarrier Oct 14, 2025
10f7e81
Add allowedEndpoints schema and tests for endpoint deduplication logic
hpyvovar-mycarrier Oct 16, 2025
d911d0f
Merge remote-tracking branch 'origin/main' into deduplication-branch
hpyvovar-mycarrier Oct 16, 2025
8222d81
Update Chart.yaml to remove dependencies section
hpyvovar-mycarrier Oct 16, 2025
86cbcfd
Remove unused helper function for wildcard path processing in _lang.tpl
hpyvovar-mycarrier Oct 16, 2025
3dc2858
Refactor wildcard path processing in helm.processPrefixPath for Istio…
hpyvovar-mycarrier Oct 16, 2025
64995c6
Improve path normalization by removing all trailing wildcards and sla…
hpyvovar-mycarrier Oct 16, 2025
ba8f522
Remove redundant health match condition in endpoint name generation
hpyvovar-mycarrier Oct 16, 2025
22a9569
fix badges in readMe
smunukutla-mycarrier Oct 16, 2025
7ce53c3
Merge branch 'main' into deduplication-branch
smunukutla-mycarrier Oct 16, 2025
66fb776
Add default C# endpoints functionality and tests; enhance allowedEndp…
hpyvovar-mycarrier Oct 16, 2025
25bab05
Refactor endpoint name processing to replace special characters for K…
hpyvovar-mycarrier Oct 17, 2025
a109fd1
Add helper functions for path normalization and regex endpoint name p…
hpyvovar-mycarrier Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![Release Charts](https://github.com/MyCarrier-DevOps/helm_charts/actions/workflows/main.yml/badge.svg)](https://github.com/MyCarrier-DevOps/helm_charts/actions/workflows/main.yml)
[![Release Charts](https://github.com/MyCarrier-DevOps/helm-charts/actions/workflows/main.yml/badge.svg)](https://github.com/MyCarrier-DevOps/helm-charts/actions/workflows/main.yml)
[![Unit Tests](https://github.com/MyCarrier-DevOps/helm-charts/actions/workflows/unit-tests.yaml/badge.svg)](https://github.com/MyCarrier-DevOps/helm-charts/actions/workflows/unit-tests.yaml)
## TL;DR

```bash
Expand Down
233 changes: 163 additions & 70 deletions charts/mycarrier-helm/templates/_lang.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -196,17 +196,60 @@
{{/*
SINGLE SOURCE OF TRUTH: Language-specific endpoint definitions
Returns YAML array that can be converted to Go data structures with fromYamlArray
Expects context with: .Values, .fullName, .application
*/}}
{{- define "helm.lang.endpoint.list" -}}
{{- if eq .Values.global.language "csharp" -}}
{{- $disableDefaults := dig "networking" "istio" "disableDefaultEndpoints" false .application -}}
{{- if and (eq .Values.global.language "csharp") (not $disableDefaults) -}}
- kind: "exact"
match: "/liveness"
- kind: "exact"
match: "/health"
{{- if contains "api" (.fullName | lower) }}
- kind: "prefix"
match: "/api"
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Helper function to normalize paths for deduplication
Removes all trailing wildcards and slashes
*/}}
{{- define "helm.normalizePath" -}}
{{- . | trimSuffix "*" | trimSuffix "/" | trimSuffix "*" | trimSuffix "/" -}}
{{- end -}}

{{/*
Helper function to process prefix paths for Istio VirtualService
Converts wildcard patterns to Istio-compatible prefix paths by replacing * with /
Generic algorithm handles all patterns consistently without hardcoded special cases
*/}}
{{- define "helm.processPrefixPath" -}}
{{- $path := . -}}
{{- /* Replace all * with / for Istio prefix matching */ -}}
{{- $processed := $path | replace "*" "/" -}}
{{- /* Remove duplicate slashes that may result from replacement */ -}}
{{- $processed | replace "//" "/" -}}
{{- end -}}

{{/*
Helper function to process endpoint names - replaces special characters for Kubernetes naming
Replaces * with "wildcard", / with -, and removes leading/trailing dashes
*/}}
{{- define "helm.processEndpointName" -}}
{{- $name := . -}}
{{- $name = $name | replace "*" "wildcard" | replace "/" "-" | trimAll "-" -}}
{{- $name -}}
{{- end -}}

{{/*
Helper function to process regex endpoint names for Kubernetes naming conventions
Replaces regex special characters with dashes and removes leading/trailing dashes
*/}}
{{- define "helm.processRegexEndpointName" -}}
{{- . | regexReplaceAll "[/\\.\\?\\+\\*]" "-" | regexReplaceAll "[\\^$]" "" | trimAll "-" -}}
{{- end -}}

{{/*
Helper template to generate VirtualService HTTP rules for language-specific and user-defined endpoints
Expand All @@ -217,98 +260,148 @@ This template generates the complete HTTP rules as strings to avoid duplication
{{- $mergedEndpoints := list -}}

{{/* Add language-specific endpoints first using centralized template */}}
{{- $langEndpointsYaml := include "helm.lang.endpoint.list" . -}}
{{- if $langEndpointsYaml -}}
{{- $langEndpoints := fromYamlArray $langEndpointsYaml -}}
{{- $mergedEndpoints = concat $mergedEndpoints $langEndpoints -}}
{{- end -}}
{{- $contextWithFullName := dict "Values" $.Values "application" $.application "fullName" $fullName }}
{{- $langEndpointsYaml := include "helm.lang.endpoint.list" $contextWithFullName | trim -}}
{{- if ne $langEndpointsYaml "" }}
{{- $langEndpoints := fromYamlArray $langEndpointsYaml -}}
{{- $mergedEndpoints = concat $mergedEndpoints $langEndpoints -}}
{{- end }}

{{/* Add user-defined endpoints */}}
{{- if and .application.networking .application.networking.istio.allowedEndpoints -}}
{{- $mergedEndpoints = concat $mergedEndpoints .application.networking.istio.allowedEndpoints -}}
{{- end -}}
{{- $mergedEndpoints = concat $mergedEndpoints .application.networking.istio.allowedEndpoints -}}
{{- end }}

{{/* Exit early if no endpoints to process */}}
{{- if not $mergedEndpoints -}}
{{- else -}}

{{/* Generate HTTP rules for each endpoint */}}
{{/* Deduplicate endpoints by kind+match */}}
{{- $seen := dict -}}
{{- $unique := list -}}
{{- range $mergedEndpoints -}}
{{- if typeIs "string" . }}
{{/* Legacy format support - treat as exact match */}}
- name: {{ $fullName }}-allowed-{{ . | replace "/" "-" | replace "*" "wildcard" | trimSuffix "-" }}
{{- if typeIs "string" . -}}
{{- if contains "*" . -}}
{{- $normalizedPath := include "helm.normalizePath" . -}}
{{- $key := printf "prefix:%s" $normalizedPath -}}
{{- if not (hasKey $seen $key) -}}
{{- $_ := set $seen $key true -}}
{{/* Store original match for proper rendering, but track normalized key */}}
{{- $unique = append $unique (dict "kind" "prefix" "match" . "normalized" $normalizedPath) -}}
{{- end -}}
{{- else -}}
{{- $key := printf "exact:%s" . -}}
{{- if not (hasKey $seen $key) -}}
{{- $_ := set $seen $key true -}}
{{- $unique = append $unique (dict "kind" "exact" "match" .) -}}
{{- end -}}
{{- end -}}
{{- else -}}
{{/* For dict endpoints, normalize match field for comparison */}}
{{- $normalizedMatch := .match -}}
{{- if eq .kind "prefix" -}}
{{- $normalizedMatch = include "helm.normalizePath" .match -}}
{{- end -}}
{{- $key := printf "%s:%s" .kind $normalizedMatch -}}
{{- if not (hasKey $seen $key) -}}
{{- $_ := set $seen $key true -}}
{{/* Store original match but track normalized */}}
{{- if eq .kind "prefix" -}}
{{- $unique = append $unique (dict "kind" .kind "match" .match "normalized" $normalizedMatch) -}}
{{- else -}}
{{- $unique = append $unique . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end }}

{{/* render HTTP rules */}}
{{- range $unique }}
{{- if eq .kind "prefix" }}
{{/* Use original match for name generation to preserve wildcards */}}
{{- $endpointName := include "helm.processEndpointName" .match -}}
{{/* Use double dash for wildcard patterns, single dash for simple prefixes */}}
{{- if contains "*" .match }}
- name: {{ $fullName }}-allowed--{{ $endpointName }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the double hyphens and trailing hyphens.

Example:

  • {{ $fullName }}-allowed--{{ $endpointName }} should be {{ $fullName }}-allowed-{{ $endpointName }}
  • {{ $fullName }}-allowed- should be {{ $fullName }}-allowed

Please update the test cases as well since this change will break them.

{{- else }}
- name: {{ $fullName }}-allowed-{{ $endpointName }}
{{- end }}
Comment on lines +324 to +328
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is no difference between the true and false case we should skip the if statement entirely.

Suggested change
{{- if contains "*" .match }}
- name: {{ $fullName }}-allowed--{{ $endpointName }}
{{- else }}
- name: {{ $fullName }}-allowed-{{ $endpointName }}
{{- end }}
- name: {{ $fullName }}-allowed-{{ $endpointName }}

match:
- uri:
{{- if contains "*" . }}
prefix: {{ . | replace "*" "" }}
{{- else }}
exact: {{ . }}
{{- end }}
- uri:
prefix: {{ include "helm.processPrefixPath" .match }}
{{- else if eq .kind "exact" }}
{{- $processedMatch := .match | replace "/" "-" | trimAll "-" }}
{{- if $processedMatch }}
- name: {{ $fullName }}-allowed--{{ $processedMatch }}
{{- else }}
{{/* New format with kind and match fields */}}
- name: {{ $fullName }}-allowed-{{ .match | replace "/" "-" | replace "*" "wildcard" | replace "(" "" | replace ")" "" | replace "|" "-" | replace "." "-" | replace "?" "-" | replace "+" "-" | replace "^" "" | replace "$" "" | trimSuffix "-" }}
- name: {{ $fullName }}-allowed-
{{- end }}
match:
- uri:
exact: {{ .match }}
{{- else if eq .kind "regex" }}
{{- $processedMatch := include "helm.processRegexEndpointName" .match }}
- name: {{ $fullName }}-allowed--{{ $processedMatch }}
match:
- uri:
{{- if eq .kind "exact" }}
exact: {{ .match }}
{{- else if eq .kind "prefix" }}
prefix: {{ .match }}
{{- else if eq .kind "regex" }}
regex: {{ .match }}
{{- else }}
{{/* Default to exact if kind is not recognized */}}
exact: {{ .match }}
{{- end }}
- uri:
regex: {{ .match }}
{{- end }}
Comment on lines +320 to 348
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The body of the match rule is identical except for the key of the operation, which means we can better follow the DRY principle by condensing all 3 of these into this:

- name: {{ $fullName }}-allowed--{{ if eq .kind "prefix" }}{{ $endpointName }}{{ else }}{{ $processedMatch }}{{ end }}
  match:
    - uri:
        {{- if eq .kind "prefix" }}
        prefix: {{ include "helm.processPrefixPath" .match }}
        {{- else if eq .kind "exact" }}
        exact: {{ .match }}
        {{- else if eq .kind "regex" }}
        regex: {{ .match }}
        {{ end }}

route:
{{- if and $.application.service $.application.service.ports }}
{{- range $.application.service.ports }}
- destination:
host: {{ $fullName }}
port:
number: {{ .port }}
weight: 100
{{- if (eq $.application.deploymentType "rollout") }}
- destination:
host: {{ $fullName }}-preview
port:
number: {{ .port }}
weight: 0
{{- end }}
{{- end }}
{{- else }}
- destination:
host: {{ $fullName }}
port:
number: {{ default 8080 (dig "ports" "http" nil $.application) }}
weight: 100
{{- if (eq $.application.deploymentType "rollout") }}
- destination:
host: {{ $fullName }}-preview
port:
number: {{ default 8080 (dig "ports" "http" nil $.application) }}
weight: 0
{{- end }}
{{- end }}
{{- if $.application.networking }}
{{- if $.application.networking.istio.enabled }}
headers:
{{- if $.application.networking }}
{{- if and $.application.networking.istio.responseHeaders }}
{{- with $.application.networking.istio.responseHeaders }}
{{ toYaml . | indent 4 | trim }}
{{- if and $.application.service $.application.service.ports }}
{{- range $.application.service.ports }}
- destination:
host: {{ $fullName }}
port:
number: {{ .port }}
weight: 100
{{- if eq $.application.deploymentType "rollout" }}
- destination:
host: {{ $fullName }}-preview
port:
number: {{ .port }}
weight: 0
{{- end }}
{{- end }}
{{- else }}
{{ include "helm.istioIngress.responseHeaders" $ | indent 4 | trim }}
- destination:
host: {{ $fullName }}
port:
number: {{ default 8080 (dig "ports" "http" nil $.application) }}
weight: 100
{{- if eq $.application.deploymentType "rollout" }}
- destination:
host: {{ $fullName }}-preview
port:
number: {{ default 8080 (dig "ports" "http" nil $.application) }}
weight: 0
{{- end }}
{{- end }}
{{- with $.application.networking.istio.corsPolicy }}
corsPolicy:
{{ toYaml . | indent 4 | trim }}
{{- end }}
{{- end }}
{{- end }}
{{/* Safely access service properties with default values if not defined */}}
timeout: {{ default "151s" (dig "service" "timeout" "151s" $.application) }}
retries:
retryOn: {{ default "5xx,reset" (dig "service" "retryOn" "5xx,reset" $.application) }}
attempts: {{ default 3 (dig "service" "attempts" 3 $.application) }}
perTryTimeout: {{ default "50s" (dig "service" "perTryTimeout" "50s" $.application) }}
{{- end }}

- name: {{ $fullName }}-forbidden
route:
- destination:
host: {{ $fullName }}
port:
number: {{ default 8080 (dig "ports" "http" nil $.application) }}
fault:
delay:
fixedDelay: 29s
percentage:
value: 100
abort:
httpStatus: 403
percentage:
value: 100
{{- end -}}
{{- end -}}
41 changes: 20 additions & 21 deletions charts/mycarrier-helm/templates/_spec_virtualservice.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ http:
port:
number: 80
headers:
{{- if and $.application.networking.istio.responseHeaders }}
{{- with $.application.networking.istio.responseHeaders }}
{{ toYaml . | indent 4 | trim }}
{{- end }}
{{- if and $.application.networking.istio.responseHeaders -}}
{{- with $.application.networking.istio.responseHeaders -}}
{{ toYaml . | indent 4 | trim -}}
{{- end -}}
{{- else }}
{{ include "helm.istioIngress.responseHeaders" $ | indent 4 | trim }}
{{- end }}
Expand All @@ -65,25 +65,24 @@ http:
{{- end }}
{{- end }}

{{- if and (not (contains "dev" $.Values.environment.name)) .application.networking .application.networking.istio .application.networking.istio.allowedEndpoints }}

{{/*
Determine if we should use allowedEndpoints logic:
1. Check if istio is enabled
2. Check if there are language-specific default endpoints (e.g., C# has /liveness, /health, /api)
3. Check if user has defined custom allowedEndpoints
*/}}
{{- $contextWithFullName := dict "Values" .Values "application" .application "fullName" $fullName }}
{{- $langEndpointsYaml := include "helm.lang.endpoint.list" $contextWithFullName | trim }}
{{- $hasLangEndpoints := ne $langEndpointsYaml "" }}
{{- $istioConfig := dig "networking" "istio" dict .application }}
{{- $hasUserEndpoints := and $istioConfig (hasKey $istioConfig "allowedEndpoints") $istioConfig.allowedEndpoints }}
{{- $istioEnabled := and .application.networking .application.networking.istio .application.networking.istio.enabled }}
{{- $hasAllowedEndpoints := and $istioEnabled (or $hasLangEndpoints $hasUserEndpoints) }}

{{- if $hasAllowedEndpoints }}
{{/* Use centralized helper template for endpoint rules generation */}}
{{ include "helm.virtualservice.allowedEndpoints" . }}
- name: {{ $fullName }}-forbidden
route:
- destination:
host: {{ $fullName }}
port:
number: {{ default 8080 (dig "ports" "http" nil .application) }}
fault:
delay:
fixedDelay: 29s
percentage:
value: 100
abort:
httpStatus: 403
percentage:
value: 100

{{- else }}
- name: {{ if (eq .application.deploymentType "rollout") }}canary{{ else }}{{ $fullName }}{{- end }}
route:
Expand Down
Loading