diff --git a/config/config.go b/config/config.go index 0cb1c9de..1ffb71c8 100644 --- a/config/config.go +++ b/config/config.go @@ -116,8 +116,8 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) { if err != nil { return } - // Check if the configuration file at least has services. - if config == nil || config.Services == nil || len(config.Services) == 0 { + // Check if the configuration file at least has services configured or Kubernetes auto discovery enabled + if config == nil || ((config.Services == nil || len(config.Services) == 0) && (config.Kubernetes == nil || !config.Kubernetes.AutoDiscover)) { err = ErrNoServiceInConfig } else { // Note that the functions below may panic, and this is on purpose to prevent Gatus from starting with @@ -132,6 +132,9 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) { func validateKubernetesConfig(config *Config) { if config.Kubernetes != nil && config.Kubernetes.AutoDiscover { + if config.Kubernetes.ServiceTemplate == nil { + panic("kubernetes.service-template cannot be nil") + } discoveredServices, err := k8s.DiscoverServices(config.Kubernetes) if err != nil { panic(err) diff --git a/k8s/client.go b/k8s/client.go index 9aa5c421..bcb5fed8 100644 --- a/k8s/client.go +++ b/k8s/client.go @@ -2,6 +2,7 @@ package k8s import ( "flag" + "fmt" "os" "path/filepath" @@ -11,21 +12,22 @@ import ( "k8s.io/client-go/tools/clientcmd" ) -func NewClient(clusterMode string) *kubernetes.Clientset { +// NewClient creates a Kubernetes client for the given ClusterMode +func NewClient(clusterMode ClusterMode) (*kubernetes.Clientset, error) { var kubeConfig *rest.Config + var err error switch clusterMode { - case "in": - kubeConfig = getInClusterConfig() - case "out": - kubeConfig = getOutClusterConfig() + case ClusterModeIn: + kubeConfig, err = getInClusterConfig() + case ClusterModeOut: + kubeConfig, err = getOutClusterConfig() default: - panic("invalid cluster mode") + return nil, fmt.Errorf("invalid cluster mode, try '%s' or '%s'", ClusterModeIn, ClusterModeOut) } - clientset, err := kubernetes.NewForConfig(kubeConfig) if err != nil { - panic(err.Error()) + return nil, fmt.Errorf("unable to get cluster config for mode '%s': %s", clusterMode, err.Error()) } - return clientset + return kubernetes.NewForConfig(kubeConfig) } func homeDir() string { @@ -35,25 +37,17 @@ func homeDir() string { return os.Getenv("USERPROFILE") // windows } -func getOutClusterConfig() *rest.Config { - var kubeconfig *string +func getOutClusterConfig() (*rest.Config, error) { + var kubeConfig *string if home := homeDir(); home != "" { - kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") + kubeConfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") } else { - kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") + kubeConfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") } flag.Parse() - config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) - if err != nil { - panic(err.Error()) - } - return config + return clientcmd.BuildConfigFromFlags("", *kubeConfig) } -func getInClusterConfig() *rest.Config { - config, err := rest.InClusterConfig() - if err != nil { - panic(err.Error()) - } - return config +func getInClusterConfig() (*rest.Config, error) { + return rest.InClusterConfig() } diff --git a/k8s/config.go b/k8s/config.go index aa7abd54..2b4679ed 100644 --- a/k8s/config.go +++ b/k8s/config.go @@ -10,11 +10,11 @@ type Config struct { // ServiceTemplate Template for auto discovered services ServiceTemplate *core.Service `yaml:"service-template"` - // ExcludeSuffix Ignore services with this suffix + // ExcludeSuffix is a slice of service suffixes that should be ignored ExcludeSuffix []string `yaml:"exclude-suffix"` // ClusterMode to authenticate with kubernetes - ClusterMode string `yaml:"cluster-mode"` + ClusterMode ClusterMode `yaml:"cluster-mode"` // Namespaces from which to discover services Namespaces []*NamespaceConfig `yaml:"namespaces"` @@ -31,3 +31,11 @@ type NamespaceConfig struct { // HealthAPI URI to append to service to reach health check API HealthAPI string `yaml:"health-api"` } + +// ClusterMode is the mode to use to authenticate to Kubernetes +type ClusterMode string + +const ( + ClusterModeIn ClusterMode = "in" + ClusterModeOut ClusterMode = "out" +) diff --git a/k8s/discovery.go b/k8s/discovery.go index 947459e3..4e71df39 100644 --- a/k8s/discovery.go +++ b/k8s/discovery.go @@ -9,7 +9,10 @@ import ( // DiscoverServices return discovered services func DiscoverServices(kubernetesConfig *Config) ([]*core.Service, error) { - client := NewClient(kubernetesConfig.ClusterMode) + client, err := NewClient(kubernetesConfig.ClusterMode) + if err != nil { + return nil, err + } services := make([]*core.Service, 0) for _, ns := range kubernetesConfig.Namespaces { kubernetesServices, err := GetKubernetesServices(client, ns.Name)