diff --git a/library/common-test/tests/service/cluster_ip_test.yaml b/library/common-test/tests/service/cluster_ip_test.yaml new file mode 100644 index 0000000000..1071199016 --- /dev/null +++ b/library/common-test/tests/service/cluster_ip_test.yaml @@ -0,0 +1,74 @@ +suite: service clusterIP test +templates: + - common.yaml +tests: + - it: should pass with type ClusterIP and custom cluster ip + set: + some_ip: 172.16.20.35 + service: + my-service: + enabled: true + primary: true + type: ClusterIP + clusterIP: "{{ .Values.some_ip }}" + ports: + port-name: + enabled: true + primary: true + workload: + my-workload: + enabled: true + primary: true + type: Deployment + podSpec: {} + asserts: + - documentIndex: &serviceDoc 1 + isKind: + of: Service + - documentIndex: *serviceDoc + isAPIVersion: + of: v1 + - documentIndex: *serviceDoc + equal: + path: metadata.name + value: release-name-common-test + - documentIndex: *serviceDoc + equal: + path: spec + value: + type: ClusterIP + clusterIP: 172.16.20.35 + + - it: should pass with type ClusterIP and ipFamilyPolicy set + set: + some_policy: PreferDualStack + some_family: IPv6 + service: + my-service: + enabled: true + primary: true + type: ClusterIP + ipFamilyPolicy: "{{ .Values.some_policy }}" + ipFamilies: + - IPv4 + - "{{ .Values.some_family }}" + ports: + port-name: + enabled: true + primary: true + workload: + my-workload: + enabled: true + primary: true + type: Deployment + podSpec: {} + asserts: + - documentIndex: *serviceDoc + equal: + path: spec + value: + type: ClusterIP + ipFamilyPolicy: PreferDualStack + ipFamilies: + - IPv4 + - IPv6 diff --git a/library/common-test/tests/service/validation_test.yaml b/library/common-test/tests/service/validation_test.yaml index 3581064f78..cf4d561630 100644 --- a/library/common-test/tests/service/validation_test.yaml +++ b/library/common-test/tests/service/validation_test.yaml @@ -201,7 +201,73 @@ tests: port-name1: enabled: true primary: true - protocol: not-a-protocol asserts: - failedTemplate: errorMessage: Service - Expected to be one of [ClusterIP, LoadBalancer, NodePort, ExternalName, ExternalIP] but got [not-a-type] + + - it: should fail with invalid ipFamilyPolicy + set: + service: + service-name1: + enabled: true + primary: true + type: ClusterIP + ipFamilyPolicy: not-a-policy + ports: + port-name1: + enabled: true + primary: true + workload: + some-pod-name: + enabled: true + primary: true + type: Deployment + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Service - Expected to be one of [SingleStack, PreferDualStack, RequireDualStack], but got [not-a-policy] + + - it: should fail with ipFamilies not a list + set: + service: + service-name1: + enabled: true + primary: true + type: ClusterIP + ipFamilies: not-a-list + ports: + port-name1: + enabled: true + primary: true + workload: + some-pod-name: + enabled: true + primary: true + type: Deployment + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Service - Expected to be a list, but got a [string] + + - it: should fail with invalid ipFamilies + set: + service: + service-name1: + enabled: true + primary: true + type: ClusterIP + ipFamilies: + - not-a-family + ports: + port-name1: + enabled: true + primary: true + workload: + some-pod-name: + enabled: true + primary: true + type: Deployment + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Service - Expected to be one of [IPv4, IPv6], but got [not-a-family] diff --git a/library/common/1.0.0/docs/service.md b/library/common/1.0.0/docs/service.md index 2a1c76641d..5e4aec2378 100644 --- a/library/common/1.0.0/docs/service.md +++ b/library/common/1.0.0/docs/service.md @@ -1,16 +1,20 @@ # Service -| Key | Type | Required | Helm Template | Default | Description | -| :------------------------------------ | :-------: | :------: | :----------------: | :---------: | :------------------------------------------------------------------------------------ | -| service | `dict` | ❌ | ❌ | `{}` | Define the service as dicts | -| service.[service-name] | `dict` | ✅ | ❌ | `{}` | Holds service definition | -| service.[service-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the service | -| service.[service-name].labels | `dict` | ❌ | ✅ (On value only) | `{}` | Additional labels for service | -| service.[service-name].annotations | `dict` | ❌ | ✅ (On value only) | `{}` | Additional annotations for service | -| service.[service-name].type | `string` | ❌ | ✅ | `ClusterIP` | Define the service type (ClusterIP, LoadBalancer, NodePort, ExternalIP, ExternalName) | -| service.[service-name].sharedKey | `string` | ❌ | ✅ | `$FullName` | Custom Shared Key for MetalLB Annotation | -| service.[service-name].targetSelector | `string` | ❌ | ✅ | `""` | Define the pod to link the service, by default will use the primary pod | -| service.[service-name].ports | `list` | ✅ | ❌ | `{}` | Define the ports of the service | +| Key | Type | Required | Helm Template | Default | Description | +| :------------------------------------------- | :-------: | :------: | :----------------: | :---------: | :------------------------------------------------------------------------------------ | +| service | `dict` | ❌ | ❌ | `{}` | Define the service as dicts | +| service.[service-name] | `dict` | ✅ | ❌ | `{}` | Holds service definition | +| service.[service-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the service | +| service.[service-name].labels | `dict` | ❌ | ✅ (On value only) | `{}` | Additional labels for service | +| service.[service-name].annotations | `dict` | ❌ | ✅ (On value only) | `{}` | Additional annotations for service | +| service.[service-name].type | `string` | ❌ | ✅ | `ClusterIP` | Define the service type (ClusterIP, LoadBalancer, NodePort, ExternalIP, ExternalName) | +| service.[service-name].sharedKey | `string` | ❌ | ✅ | `$FullName` | Custom Shared Key for MetalLB Annotation | +| service.[service-name].clusterIP | `string` | ❌ | ✅ | | Custom Cluster IP | +| service.[service-name].ipFamilyPolicy | `string` | ❌ | ✅ | | Define the ipFamilyPolicy (SingleStack, PreferDualStack, RequireDualStack) | +| service.[service-name].ipFamilies | `list` | ❌ | ❌ | | Define the ipFamilies | +| service.[service-name].ipFamilies.[ipFamily] | `string` | ❌ | ✅ | | Define the ipFamily (IPv4, IPv6) | +| service.[service-name].targetSelector | `string` | ❌ | ✅ | `""` | Define the pod to link the service, by default will use the primary pod | +| service.[service-name].ports | `list` | ✅ | ❌ | `{}` | Define the ports of the service | --- diff --git a/library/common/1.0.0/templates/classes/_service.tpl b/library/common/1.0.0/templates/classes/_service.tpl index c2a85a57b9..b98be81608 100644 --- a/library/common/1.0.0/templates/classes/_service.tpl +++ b/library/common/1.0.0/templates/classes/_service.tpl @@ -12,6 +12,8 @@ objectData: The service data, that will be used to render the Service object. {{- $objectData := .objectData -}} {{- $svcType := $objectData.type | default "ClusterIP" -}} + {{/* Expand svcType in case it has tpl */}} + {{- $svcType = (tpl $svcType $rootCtx) -}} {{/* Get Pod Values based on the selector (or the absence of it) */}} {{- $podValues := fromJson (include "ix.v1.common.lib.service.getSelectedPodValues" (dict "rootCtx" $rootCtx "objectData" $objectData)) -}} @@ -66,9 +68,11 @@ metadata: {{- . | nindent 4 }} {{- end }} spec: -{{- if not (mustHas $svcType (list "ExternalName" "ExternalIP")) }} + {{- if eq $svcType "ClusterIP" -}} + {{- include "ix.v1.common.lib.service.clusterIP" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 2 }} + {{- end }} + {{- if not (mustHas $svcType (list "ExternalName" "ExternalIP")) }} selector: - {{- include "ix.v1.common.lib.metadata.selectorLabels" (dict "rootCtx" $rootCtx "podName" $podValues.shortName) | trim | nindent 2 }} -{{- end -}} -{{/* TODO: */}} + {{- include "ix.v1.common.lib.metadata.selectorLabels" (dict "rootCtx" $rootCtx "podName" $podValues.shortName) | trim | nindent 2 }} + {{- end -}} {{- end -}} diff --git a/library/common/1.0.0/templates/lib/service/_ipFamily.tpl b/library/common/1.0.0/templates/lib/service/_ipFamily.tpl new file mode 100644 index 0000000000..ed264518d4 --- /dev/null +++ b/library/common/1.0.0/templates/lib/service/_ipFamily.tpl @@ -0,0 +1,38 @@ +{{/* Service - ipFamily */}} +{{/* Call this template: +{{ include "ix.v1.common.lib.service.ipFamily" (dict "rootCtx" $rootCtx "objectData" $objectData) -}} +rootCtx: The root context of the service +objectData: The service object data +*/}} + +{{- define "ix.v1.common.lib.service.ipFamily" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} + + {{- with $objectData.ipFamilyPolicy -}} + {{- $famPolicy := tpl . $rootCtx -}} + + {{- $stacks := (list "SingleStack" "PreferDualStack" "RequireDualStack") -}} + {{- if not (mustHas $famPolicy $stacks) -}} + {{- fail (printf "Service - Expected to be one of [%s], but got [%s]" (join ", " $stacks) $famPolicy) -}} + {{- end }} +ipFamilyPolicy: {{ $famPolicy }} + {{- end -}} + + {{- if and $objectData.ipFamilies (not (kindIs "slice" $objectData.ipFamilies)) -}} + {{- fail (printf "Service - Expected to be a list, but got a [%s]" (kindOf $objectData.ipFamilies)) -}} + {{- end -}} + + {{- with $objectData.ipFamilies }} +ipFamilies: + {{- range . }} + {{- $ipFam := tpl . $rootCtx -}} + + {{- $stacks := (list "IPv4" "IPv6") -}} + {{- if not (mustHas $ipFam $stacks) -}} + {{- fail (printf "Service - Expected to be one of [%s], but got [%s]" (join ", " $stacks) $ipFam) -}} + {{- end }} + - {{ $ipFam }} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/1.0.0/templates/lib/service/_validation.tpl b/library/common/1.0.0/templates/lib/service/_validation.tpl index 8613d57cce..78ae1240ee 100644 --- a/library/common/1.0.0/templates/lib/service/_validation.tpl +++ b/library/common/1.0.0/templates/lib/service/_validation.tpl @@ -18,7 +18,12 @@ objectData: {{- end -}} {{- if and $objectData.targetSelector (not (kindIs "string" $objectData.targetSelector)) -}} - {{- fail (printf "Service - Expected service's to be [string], but got [%s]" (kindOf $objectData.targetSelector)) -}} + {{- fail (printf "Service - Expected to be [string], but got [%s]" (kindOf $objectData.targetSelector)) -}} + {{- end -}} + + {{- $svcTypes := (list "ClusterIP" "LoadBalancer" "NodePort" "ExternalName" "ExternalIP") -}} + {{- if and $objectData.type (not (mustHas $objectData.type $svcTypes)) -}} + {{- fail (printf "Service - Expected to be one of [%s] but got [%s]" (join ", " $svcTypes) $objectData.type) -}} {{- end -}} {{- $hasEnabledPort := false -}} @@ -27,11 +32,12 @@ objectData: {{- $hasEnabledPort = true -}} {{- if and $port.targetSelector (not (kindIs "string" $port.targetSelector)) -}} - {{- fail (printf "Service - Expected port's to be [string], but got [%s]" (kindOf $port.targetSelector)) -}} + {{- fail (printf "Service - Expected to be [string], but got [%s]" (kindOf $port.targetSelector)) -}} {{- end -}} - {{- if and $port.protocol (not (mustHas $port.protocol (list "TCP" "UDP" "HTTP" "HTTPS"))) -}} - {{- fail (printf "Service - Expected port's protocol to be one of [TCP, UDP, HTTP, HTTPS] but got [%s]" $port.protocol) -}} + {{- $protocolTypes := (list "TCP" "UDP" "HTTP" "HTTPS") -}} + {{- if and $port.protocol (not (mustHas $port.protocol $protocolTypes)) -}} + {{- fail (printf "Service - Expected to be one of [%s] but got [%s]" (join ", " $protocolTypes) $port.protocol) -}} {{- end -}} {{- end -}} diff --git a/library/common/1.0.0/templates/lib/service/serviceTypes/_clusterIP.tpl b/library/common/1.0.0/templates/lib/service/serviceTypes/_clusterIP.tpl new file mode 100644 index 0000000000..297900810f --- /dev/null +++ b/library/common/1.0.0/templates/lib/service/serviceTypes/_clusterIP.tpl @@ -0,0 +1,17 @@ +{{/* Service - ClusterIP */}} +{{/* Call this template: +{{ include "ix.v1.common.lib.service.clusterIP" (dict "rootCtx" $rootCtx "objectData" $objectData) -}} +rootCtx: The root context of the service +objectData: The service object data +*/}} + +{{- define "ix.v1.common.lib.service.clusterIP" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} + +type: ClusterIP + {{- with $objectData.clusterIP }} +clusterIP: {{ tpl . $rootCtx }} + {{- end -}} + {{- include "ix.v1.common.lib.service.ipFamily" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 0 }} +{{- end -}}