internal/manifests/collector/adapters/config_to_probe.go (121 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package adapters
import (
"errors"
"strings"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
var (
errNoService = errors.New("no service available as part of the configuration")
errNoExtensions = errors.New("no extensions available as part of the configuration")
errServiceNotAMap = errors.New("service property in the configuration doesn't contain valid services")
errExtensionsNotAMap = errors.New("extensions property in the configuration doesn't contain valid extensions")
errNoExtensionHealthCheck = errors.New("extensions property in the configuration does not contain the expected health_check extension")
ErrNoServiceExtensions = errors.New("service property in the configuration doesn't contain extensions")
errServiceExtensionsNotSlice = errors.New("service extensions property in the configuration does not contain valid extensions")
ErrNoServiceExtensionHealthCheck = errors.New("no healthcheck extension available in service extension configuration")
)
type probeConfiguration struct {
path string
port intstr.IntOrString
}
const (
defaultHealthCheckPath = "/"
defaultHealthCheckPort = 13133
)
// ConfigToContainerProbe converts the incoming configuration object into a container probe or returns an error.
func ConfigToContainerProbe(config map[interface{}]interface{}) (*corev1.Probe, error) {
serviceProperty, withService := config["service"]
if !withService {
return nil, errNoService
}
service, withSvcProperty := serviceProperty.(map[interface{}]interface{})
if !withSvcProperty {
return nil, errServiceNotAMap
}
serviceExtensionsProperty, withExtension := service["extensions"]
if !withExtension {
return nil, ErrNoServiceExtensions
}
serviceExtensions, withExtProperty := serviceExtensionsProperty.([]interface{})
if !withExtProperty {
return nil, errServiceExtensionsNotSlice
}
healthCheckServiceExtensions := make([]string, 0)
for _, ext := range serviceExtensions {
parsedExt, ok := ext.(string)
if ok && strings.HasPrefix(parsedExt, "health_check") {
healthCheckServiceExtensions = append(healthCheckServiceExtensions, parsedExt)
}
}
if len(healthCheckServiceExtensions) == 0 {
return nil, ErrNoServiceExtensionHealthCheck
}
extensionsProperty, ok := config["extensions"]
if !ok {
return nil, errNoExtensions
}
extensions, ok := extensionsProperty.(map[interface{}]interface{})
if !ok {
return nil, errExtensionsNotAMap
}
// in the event of multiple health_check service extensions defined, we arbitrarily take the first one found
for _, healthCheckForProbe := range healthCheckServiceExtensions {
healthCheckExtension, ok := extensions[healthCheckForProbe]
if ok {
return createProbeFromExtension(healthCheckExtension)
}
}
return nil, errNoExtensionHealthCheck
}
func createProbeFromExtension(extension interface{}) (*corev1.Probe, error) {
probeCfg := extractProbeConfigurationFromExtension(extension)
return &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: probeCfg.path,
Port: probeCfg.port,
},
},
}, nil
}
func extractProbeConfigurationFromExtension(ext interface{}) probeConfiguration {
extensionCfg, ok := ext.(map[interface{}]interface{})
if !ok {
return defaultProbeConfiguration()
}
return probeConfiguration{
path: extractPathFromExtensionConfig(extensionCfg),
port: extractPortFromExtensionConfig(extensionCfg),
}
}
func defaultProbeConfiguration() probeConfiguration {
return probeConfiguration{
path: defaultHealthCheckPath,
port: intstr.FromInt(defaultHealthCheckPort),
}
}
func extractPathFromExtensionConfig(cfg map[interface{}]interface{}) string {
if path, ok := cfg["path"]; ok {
if parsedPath, ok := path.(string); ok {
return parsedPath
}
}
return defaultHealthCheckPath
}
func extractPortFromExtensionConfig(cfg map[interface{}]interface{}) intstr.IntOrString {
endpoint, ok := cfg["endpoint"]
if !ok {
return defaultHealthCheckEndpoint()
}
parsedEndpoint, ok := endpoint.(string)
if !ok {
return defaultHealthCheckEndpoint()
}
endpointComponents := strings.Split(parsedEndpoint, ":")
if len(endpointComponents) != 2 {
return defaultHealthCheckEndpoint()
}
return intstr.Parse(endpointComponents[1])
}
func defaultHealthCheckEndpoint() intstr.IntOrString {
return intstr.FromInt(defaultHealthCheckPort)
}