Skip to content

Commit

Permalink
Add custom HealthCheck conversion.
Browse files Browse the repository at this point in the history
  • Loading branch information
sawsa307 committed Sep 19, 2024
1 parent cb9abdf commit 315edd5
Show file tree
Hide file tree
Showing 5 changed files with 474 additions and 18 deletions.
49 changes: 49 additions & 0 deletions pkg/i2gw/providers/gce/extensions/output_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,52 @@ func BuildBackendPolicySecurityPolicyConfig(serviceIR intermediate.ProviderSpeci
securityPolicy := serviceIR.Gce.SecurityPolicy.Name
return &securityPolicy
}

func BuildHealthCheckPolicyConfig(serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.HealthCheckPolicyConfig {
hcConfig := gkegatewayv1.HealthCheckPolicyConfig{
CheckIntervalSec: serviceIR.Gce.HealthCheck.CheckIntervalSec,
TimeoutSec: serviceIR.Gce.HealthCheck.TimeoutSec,
HealthyThreshold: serviceIR.Gce.HealthCheck.HealthyThreshold,
UnhealthyThreshold: serviceIR.Gce.HealthCheck.UnhealthyThreshold,
}
commonHc := gkegatewayv1.CommonHealthCheck{
Port: serviceIR.Gce.HealthCheck.Port,
}
commonHTTPHc := gkegatewayv1.CommonHTTPHealthCheck{
RequestPath: serviceIR.Gce.HealthCheck.RequestPath,
}

switch *serviceIR.Gce.HealthCheck.Type {
case "HTTP":
hcConfig.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP,
HTTP: &gkegatewayv1.HTTPHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}

case "HTTPS":
hcConfig.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTPS,
HTTPS: &gkegatewayv1.HTTPSHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}

case "HTTP2":
hcConfig.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP2,
HTTP2: &gkegatewayv1.HTTP2HealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}

default:
return nil
}

return &hcConfig
}
58 changes: 51 additions & 7 deletions pkg/i2gw/providers/gce/gateway_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package gce

import (
"fmt"

gkegatewayv1 "github.com/GoogleCloudPlatform/gke-gateway-api/apis/networking/v1"
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/intermediate"
Expand Down Expand Up @@ -49,22 +51,36 @@ func (c *irToGatewayResourcesConverter) irToGateway(ir intermediate.IR) (i2gw.Ga
func buildGceServiceExtensions(ir intermediate.IR, gatewayResources *i2gw.GatewayResources) {
for svcKey, serviceIR := range ir.Services {
bePolicy := addBackendPolicyIfConfigured(svcKey, serviceIR)
if bePolicy == nil {
continue
if bePolicy != nil {
obj, err := i2gw.CastToUnstructured(bePolicy)
if err != nil {
notify(notifications.ErrorNotification, "Failed to cast GCPBackendPolicy to unstructured", bePolicy)
continue
}
gatewayResources.GatewayExtensions = append(gatewayResources.GatewayExtensions, *obj)
}
obj, err := i2gw.CastToUnstructured(bePolicy)
if err != nil {
notify(notifications.ErrorNotification, "Failed to cast GCPBackendPolicy to unstructured", bePolicy)
continue

hcPolicy := addHealthCheckPolicyIfConfigured(svcKey, serviceIR)
if hcPolicy != nil {
obj, err := i2gw.CastToUnstructured(hcPolicy)
if err != nil {
notify(notifications.ErrorNotification, "Failed to cast HealthCheckPolicy to unstructured", hcPolicy)
continue
}
gatewayResources.GatewayExtensions = append(gatewayResources.GatewayExtensions, *obj)
}
gatewayResources.GatewayExtensions = append(gatewayResources.GatewayExtensions, *obj)
}
}

func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.GCPBackendPolicy {
if serviceIR.Gce == nil {
return nil
}
// If there is no specification related to GCPBackendPolicy feature, return nil.
if serviceIR.Gce.SessionAffinity == nil && serviceIR.Gce.SecurityPolicy == nil {
return nil
}

backendPolicy := gkegatewayv1.GCPBackendPolicy{
ObjectMeta: metav1.ObjectMeta{
Namespace: serviceNamespacedName.Namespace,
Expand All @@ -90,3 +106,31 @@ func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, se

return &backendPolicy
}

func addHealthCheckPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.HealthCheckPolicy {
if serviceIR.Gce == nil {
return nil
}
// If there is no specification related to HealthCheckPolicy feature, return nil.
if serviceIR.Gce.HealthCheck == nil {
return nil
}

healthCheckPolicy := gkegatewayv1.HealthCheckPolicy{
ObjectMeta: metav1.ObjectMeta{
Namespace: serviceNamespacedName.Namespace,
Name: serviceNamespacedName.Name,
},
Spec: gkegatewayv1.HealthCheckPolicySpec{
Default: extensions.BuildHealthCheckPolicyConfig(serviceIR),
TargetRef: gatewayv1alpha2.NamespacedPolicyTargetReference{
Group: "",
Kind: "Service",
Name: gatewayv1.ObjectName(serviceNamespacedName.Name),
},
},
}
healthCheckPolicy.SetGroupVersionKind(HealthCheckPolicyGVK)
fmt.Println(healthCheckPolicy)
return &healthCheckPolicy
}
239 changes: 239 additions & 0 deletions pkg/i2gw/providers/gce/gateway_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,107 @@ var (
},
},
}

commonHc = gkegatewayv1.CommonHealthCheck{
Port: common.PtrTo(testPort),
}
commonHTTPHc = gkegatewayv1.CommonHTTPHealthCheck{
RequestPath: common.PtrTo(testRequestPath),
}

testHealthCheckPolicyName = testServiceName
testHealthCheckPolicyHTTP = gkegatewayv1.HealthCheckPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "networking.gke.io/v1",
Kind: "HealthCheckPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testHealthCheckPolicyName,
},
Spec: gkegatewayv1.HealthCheckPolicySpec{
Default: &gkegatewayv1.HealthCheckPolicyConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Config: &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP,
HTTP: &gkegatewayv1.HTTPHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
},
},
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
Group: "",
Kind: "Service",
Name: gatewayv1.ObjectName(testServiceName),
},
},
}

testHealthCheckPolicyHTTPS = gkegatewayv1.HealthCheckPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "networking.gke.io/v1",
Kind: "HealthCheckPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testHealthCheckPolicyName,
},
Spec: gkegatewayv1.HealthCheckPolicySpec{
Default: &gkegatewayv1.HealthCheckPolicyConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Config: &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTPS,
HTTPS: &gkegatewayv1.HTTPSHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
},
},
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
Group: "",
Kind: "Service",
Name: gatewayv1.ObjectName(testServiceName),
},
},
}

testHealthCheckPolicyHTTP2 = gkegatewayv1.HealthCheckPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "networking.gke.io/v1",
Kind: "HealthCheckPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testHealthCheckPolicyName,
},
Spec: gkegatewayv1.HealthCheckPolicySpec{
Default: &gkegatewayv1.HealthCheckPolicyConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Config: &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP2,
HTTP2: &gkegatewayv1.HTTP2HealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
},
},
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
Group: "",
Kind: "Service",
Name: gatewayv1.ObjectName(testServiceName),
},
},
}
)

func Test_irToGateway(t *testing.T) {
Expand All @@ -171,6 +272,18 @@ func Test_irToGateway(t *testing.T) {
if err != nil {
t.Errorf("Failed to generate unstructured GCP Backend Policy with Security Policy feature: %v", err)
}
testHealthCheckPolicyHTTPUnstructured, err := i2gw.CastToUnstructured(&testHealthCheckPolicyHTTP)
if err != nil {
t.Errorf("Failed to generate unstructured Health Check Policy with custom HTTP health check: %v", err)
}
testHealthCheckPolicyHTTPSUnstructured, err := i2gw.CastToUnstructured(&testHealthCheckPolicyHTTPS)
if err != nil {
t.Errorf("Failed to generate unstructured Health Check Policy with custom HTTP health check: %v", err)
}
testHealthCheckPolicyHTTP2Unstructured, err := i2gw.CastToUnstructured(&testHealthCheckPolicyHTTP2)
if err != nil {
t.Errorf("Failed to generate unstructured Health Check Policy with custom HTTP2 health check: %v", err)
}

testCases := []struct {
name string
Expand Down Expand Up @@ -287,6 +400,132 @@ func Test_irToGateway(t *testing.T) {
},
expectedErrors: field.ErrorList{},
},
{
name: "ingress with a Backend Config specifying custom HTTP health check",
ir: intermediate.IR{
Gateways: map[types.NamespacedName]intermediate.GatewayContext{
{Namespace: testNamespace, Name: testGatewayName}: {
Gateway: testGateway,
},
},
HTTPRoutes: map[types.NamespacedName]intermediate.HTTPRouteContext{
{Namespace: testNamespace, Name: testHTTPRouteName}: {
HTTPRoute: testHTTPRoute,
},
},
Services: map[types.NamespacedName]intermediate.ProviderSpecificServiceIR{
{Namespace: testNamespace, Name: testServiceName}: {
Gce: &intermediate.GceServiceIR{
HealthCheck: &intermediate.HealthCheckConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Type: common.PtrTo(protocolHTTP),
Port: common.PtrTo(testPort),
RequestPath: common.PtrTo(testRequestPath),
},
},
},
},
},
expectedGatewayResources: i2gw.GatewayResources{
Gateways: map[types.NamespacedName]gatewayv1.Gateway{
{Namespace: testNamespace, Name: testGatewayName}: testGateway,
},
HTTPRoutes: map[types.NamespacedName]gatewayv1.HTTPRoute{
{Namespace: testNamespace, Name: testHTTPRouteName}: testHTTPRoute,
},
GatewayExtensions: []unstructured.Unstructured{
*testHealthCheckPolicyHTTPUnstructured,
},
},
expectedErrors: field.ErrorList{},
},
{
name: "ingress with a Backend Config specifying custom HTTPS health check",
ir: intermediate.IR{
Gateways: map[types.NamespacedName]intermediate.GatewayContext{
{Namespace: testNamespace, Name: testGatewayName}: {
Gateway: testGateway,
},
},
HTTPRoutes: map[types.NamespacedName]intermediate.HTTPRouteContext{
{Namespace: testNamespace, Name: testHTTPRouteName}: {
HTTPRoute: testHTTPRoute,
},
},
Services: map[types.NamespacedName]intermediate.ProviderSpecificServiceIR{
{Namespace: testNamespace, Name: testServiceName}: {
Gce: &intermediate.GceServiceIR{
HealthCheck: &intermediate.HealthCheckConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Type: common.PtrTo(protocolHTTPS),
Port: common.PtrTo(testPort),
RequestPath: common.PtrTo(testRequestPath),
},
},
},
},
},
expectedGatewayResources: i2gw.GatewayResources{
Gateways: map[types.NamespacedName]gatewayv1.Gateway{
{Namespace: testNamespace, Name: testGatewayName}: testGateway,
},
HTTPRoutes: map[types.NamespacedName]gatewayv1.HTTPRoute{
{Namespace: testNamespace, Name: testHTTPRouteName}: testHTTPRoute,
},
GatewayExtensions: []unstructured.Unstructured{
*testHealthCheckPolicyHTTPSUnstructured,
},
},
expectedErrors: field.ErrorList{},
},
{
name: "ingress with a Backend Config specifying custom HTTP2 health check",
ir: intermediate.IR{
Gateways: map[types.NamespacedName]intermediate.GatewayContext{
{Namespace: testNamespace, Name: testGatewayName}: {
Gateway: testGateway,
},
},
HTTPRoutes: map[types.NamespacedName]intermediate.HTTPRouteContext{
{Namespace: testNamespace, Name: testHTTPRouteName}: {
HTTPRoute: testHTTPRoute,
},
},
Services: map[types.NamespacedName]intermediate.ProviderSpecificServiceIR{
{Namespace: testNamespace, Name: testServiceName}: {
Gce: &intermediate.GceServiceIR{
HealthCheck: &intermediate.HealthCheckConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
Type: common.PtrTo(protocolHTTP2),
Port: common.PtrTo(testPort),
RequestPath: common.PtrTo(testRequestPath),
},
},
},
},
},
expectedGatewayResources: i2gw.GatewayResources{
Gateways: map[types.NamespacedName]gatewayv1.Gateway{
{Namespace: testNamespace, Name: testGatewayName}: testGateway,
},
HTTPRoutes: map[types.NamespacedName]gatewayv1.HTTPRoute{
{Namespace: testNamespace, Name: testHTTPRouteName}: testHTTPRoute,
},
GatewayExtensions: []unstructured.Unstructured{
*testHealthCheckPolicyHTTP2Unstructured,
},
},
expectedErrors: field.ErrorList{},
},
}

for _, tc := range testCases {
Expand Down
Loading

0 comments on commit 315edd5

Please sign in to comment.