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 30, 2024
1 parent a59e7de commit 2d242c0
Show file tree
Hide file tree
Showing 5 changed files with 426 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
}
55 changes: 48 additions & 7 deletions pkg/i2gw/providers/gce/gateway_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,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 +104,30 @@ 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)
return &healthCheckPolicy
}
194 changes: 194 additions & 0 deletions pkg/i2gw/providers/gce/gateway_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,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{
getTestHealthCheckPolicyUnstrctured(testNamespace, testServiceName, protocolHTTP),
},
},
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{
getTestHealthCheckPolicyUnstrctured(testNamespace, testServiceName, protocolHTTPS),
},
},
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{
getTestHealthCheckPolicyUnstrctured(testNamespace, testServiceName, protocolHTTP2),
},
},
expectedErrors: field.ErrorList{},
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -354,3 +480,71 @@ func Test_irToGateway(t *testing.T) {
})
}
}

// getTestHealthCheckPolicyUnstrctured returns the template HealthCheckPolicy
// based on the protocol and the service it attaches to.
func getTestHealthCheckPolicyUnstrctured(serviceNamespace, serviceName, protocol string) unstructured.Unstructured {
commonHc := gkegatewayv1.CommonHealthCheck{
Port: common.PtrTo(testPort),
}
commonHTTPHc := gkegatewayv1.CommonHTTPHealthCheck{
RequestPath: common.PtrTo(testRequestPath),
}

hcPolicy := gkegatewayv1.HealthCheckPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "networking.gke.io/v1",
Kind: "HealthCheckPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: serviceNamespace,
Name: serviceName, // Converted Health Check Policy will share the name of the service it attaches to.
},
Spec: gkegatewayv1.HealthCheckPolicySpec{
Default: &gkegatewayv1.HealthCheckPolicyConfig{
CheckIntervalSec: common.PtrTo(testCheckIntervalSec),
TimeoutSec: common.PtrTo(testTimeoutSec),
HealthyThreshold: common.PtrTo(testHealthyThreshold),
UnhealthyThreshold: common.PtrTo(testUnhealthyThreshold),
},
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
Group: "",
Kind: "Service",
Name: gatewayv1.ObjectName(serviceName),
},
},
}
if protocol == protocolHTTP {
hcPolicy.Spec.Default.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP,
HTTP: &gkegatewayv1.HTTPHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}
} else if protocol == protocolHTTPS {
hcPolicy.Spec.Default.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTPS,
HTTPS: &gkegatewayv1.HTTPSHealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}
} else if protocol == protocolHTTP2 {
hcPolicy.Spec.Default.Config = &gkegatewayv1.HealthCheck{
Type: gkegatewayv1.HTTP2,
HTTP2: &gkegatewayv1.HTTP2HealthCheck{
CommonHealthCheck: commonHc,
CommonHTTPHealthCheck: commonHTTPHc,
},
}
} else {
return unstructured.Unstructured{}
}
hcPolicyUnstructured, err := i2gw.CastToUnstructured(&hcPolicy)
if err != nil {
return unstructured.Unstructured{}
}

return *hcPolicyUnstructured
}
Loading

0 comments on commit 2d242c0

Please sign in to comment.