Skip to content

Commit

Permalink
Merge pull request #426 from abansal4032/health-check-monitor
Browse files Browse the repository at this point in the history
Add health-check-monitor
  • Loading branch information
k8s-ci-robot authored May 28, 2020
2 parents 1d03b66 + 44dc4aa commit 452818c
Show file tree
Hide file tree
Showing 9 changed files with 630 additions and 2 deletions.
13 changes: 11 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ endif
-tags "$(BUILD_TAGS)" \
./test/e2e/problemmaker/problem_maker.go

./bin/health-checker: $(PKG_SOURCES)
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GO111MODULE=on go build \
-mod vendor \
-o bin/health-checker \
-ldflags '-X $(PKG)/pkg/version.version=$(VERSION)' \
-tags "$(BUILD_TAGS)" \
cmd/healthchecker/health_checker.go

Dockerfile: Dockerfile.in
sed -e 's|@BASEIMAGE@|$(BASEIMAGE)|g' $< >$@
ifneq ($(ENABLE_JOURNALD), 1)
Expand All @@ -134,12 +142,12 @@ e2e-test: vet fmt build-tar
-boskos-project-type=$(BOSKOS_PROJECT_TYPE) -job-name=$(JOB_NAME) \
-artifacts-dir=$(ARTIFACTS)

build-binaries: ./bin/node-problem-detector ./bin/log-counter
build-binaries: ./bin/node-problem-detector ./bin/log-counter ./bin/health-checker

build-container: build-binaries Dockerfile
docker build -t $(IMAGE) .

build-tar: ./bin/node-problem-detector ./bin/log-counter ./test/bin/problem-maker
build-tar: ./bin/node-problem-detector ./bin/log-counter ./bin/health-checker ./test/bin/problem-maker
tar -zcvf $(TARBALL) bin/ config/ test/e2e-install.sh test/bin/problem-maker
sha1sum $(TARBALL)
md5sum $(TARBALL)
Expand All @@ -164,6 +172,7 @@ push-tar: build-tar
push: push-container push-tar

clean:
rm -f bin/health-checker
rm -f bin/log-counter
rm -f bin/node-problem-detector
rm -f test/bin/problem-maker
Expand Down
57 changes: 57 additions & 0 deletions cmd/healthchecker/health_checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"flag"
"fmt"
"os"

"github.com/spf13/pflag"

"k8s.io/node-problem-detector/cmd/healthchecker/options"
"k8s.io/node-problem-detector/pkg/custompluginmonitor/types"
"k8s.io/node-problem-detector/pkg/healthchecker"
)

func main() {
// Set glog flag so that it does not log to files.
if err := flag.Set("logtostderr", "true"); err != nil {
fmt.Printf("Failed to set logtostderr=true: %v", err)
os.Exit(int(types.Unknown))
}

hco := options.NewHealthCheckerOptions()
hco.AddFlags(pflag.CommandLine)
pflag.Parse()
hco.SetDefaults()
if err := hco.IsValid(); err != nil {
fmt.Println(err)
os.Exit(int(types.Unknown))
}

hc, err := healthchecker.NewHealthChecker(hco)
if err != nil {
fmt.Println(err)
os.Exit(int(types.Unknown))
}
if !hc.CheckHealth() {
fmt.Printf("%v:%v was found unhealthy; repair flag : %v\n", hco.Component, hco.SystemdService, hco.EnableRepair)
os.Exit(int(types.NonOK))
}
os.Exit(int(types.OK))
}
102 changes: 102 additions & 0 deletions cmd/healthchecker/options/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
"flag"
"fmt"
"time"

"github.com/spf13/pflag"

"k8s.io/node-problem-detector/pkg/healthchecker/types"
)

// NewHealthCheckerOptions returns an empty health check options struct.
func NewHealthCheckerOptions() *HealthCheckerOptions {
return &HealthCheckerOptions{}
}

// HealthCheckerOptions are the options used to configure the health checker.
type HealthCheckerOptions struct {
Component string
SystemdService string
EnableRepair bool
CriCtlPath string
CriSocketPath string
CoolDownTime time.Duration
HealthCheckTimeout time.Duration
}

// AddFlags adds health checker command line options to pflag.
func (hco *HealthCheckerOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&hco.Component, "component", types.KubeletComponent,
"The component to check health for. Supports kubelet, docker and cri")
fs.StringVar(&hco.SystemdService, "systemd-service", "",
"The underlying systemd service responsible for the component. Set to the corresponding component for docker and kubelet, containerd for cri.")
fs.BoolVar(&hco.EnableRepair, "enable-repair", true, "Flag to enable/disable repair attempt for the component.")
fs.StringVar(&hco.CriCtlPath, "crictl-path", types.DefaultCriCtl,
"The path to the crictl binary. This is used to check health of cri component.")
fs.StringVar(&hco.CriSocketPath, "cri-socket-path", types.DefaultCriSocketPath,
"The path to the cri socket. Used with crictl to specify the socket path.")
fs.DurationVar(&hco.CoolDownTime, "cooldown-time", types.DefaultCoolDownTime,
"The duration to wait for the service to be up before attempting repair.")
fs.DurationVar(&hco.HealthCheckTimeout, "health-check-timeout", types.DefaultHealthCheckTimeout,
"The time to wait before marking the component as unhealthy.")
}

// IsValid validates health checker command line options.
// Returns error if invalid, nil otherwise.
func (hco *HealthCheckerOptions) IsValid() error {
// Make sure the component specified is valid.
if hco.Component != types.KubeletComponent && hco.Component != types.DockerComponent && hco.Component != types.CRIComponent {
return fmt.Errorf("the component specified is not supported. Supported components are : <kubelet/docker/cri>")
}
// Make sure the systemd service is specified if repair is enabled.
if hco.EnableRepair && hco.SystemdService == "" {
return fmt.Errorf("systemd-service cannot be empty when repair is enabled")
}
// Skip checking further if the component is not cri.
if hco.Component != types.CRIComponent {
return nil
}
// Make sure the crictl path is not empty for cri component.
if hco.Component == types.CRIComponent && hco.CriCtlPath == "" {
return fmt.Errorf("the crictl-path cannot be empty for cri component")
}
// Make sure the cri socker path is not empty for cri component.
if hco.Component == types.CRIComponent && hco.CriSocketPath == "" {
return fmt.Errorf("the cri-socket-path cannot be empty for cri component")
}
return nil
}

// SetDefaults sets the defaults values for the dependent flags.
func (hco *HealthCheckerOptions) SetDefaults() {
if hco.SystemdService != "" {
return
}
if hco.Component != types.CRIComponent {
hco.SystemdService = hco.Component
return
}
hco.SystemdService = types.ContainerdService
}

func init() {
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
}
76 changes: 76 additions & 0 deletions cmd/healthchecker/options/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
"testing"

"github.com/stretchr/testify/assert"

"k8s.io/node-problem-detector/pkg/healthchecker/types"
)

func TestIsValid(t *testing.T) {
testCases := []struct {
name string
hco HealthCheckerOptions
expectError bool
}{
{
name: "valid component",
hco: HealthCheckerOptions{
Component: types.KubeletComponent,
},
expectError: false,
},
{
name: "invalid component",
hco: HealthCheckerOptions{
Component: "wrongComponent",
},
expectError: true,
},
{
name: "empty crictl-path with cri",
hco: HealthCheckerOptions{
Component: types.CRIComponent,
CriCtlPath: "",
EnableRepair: false,
},
expectError: true,
},
{
name: "empty systemd-service and repair enabled",
hco: HealthCheckerOptions{
Component: types.KubeletComponent,
EnableRepair: true,
SystemdService: "",
},
expectError: true,
},
}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
if test.expectError {
assert.Error(t, test.hco.IsValid(), "HealthChecker option %+v is invalid. Expected IsValid to return error.", test.hco)
} else {
assert.NoError(t, test.hco.IsValid(), "HealthChecker option %+v is valid. Expected IsValid to return nil.", test.hco)
}
})
}
}
33 changes: 33 additions & 0 deletions config/health-checker-docker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"plugin": "custom",
"pluginConfig": {
"invoke_interval": "10s",
"timeout": "3m",
"max_output_length": 80,
"concurrency": 1
},
"source": "health-checker",
"metricsReporting": true,
"conditions": [
{
"type": "ContainerRuntimeUnhealthy",
"reason": "ContainerRuntimeIsHealthy",
"message": "Container runtime on the node is functioning properly"
}
],
"rules": [
{
"type": "permanent",
"condition": "ContainerRuntimeUnhealthy",
"reason": "DockerUnhealthy",
"path": "/home/kubernetes/bin/health-checker",
"args": [
"--component=docker",
"--enable-repair=false",
"--cooldown-time=2m",
"--health-check-timeout=60s"
],
"timeout": "3m"
}
]
}
33 changes: 33 additions & 0 deletions config/health-checker-kubelet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"plugin": "custom",
"pluginConfig": {
"invoke_interval": "10s",
"timeout": "3m",
"max_output_length": 80,
"concurrency": 1
},
"source": "health-checker",
"metricsReporting": true,
"conditions": [
{
"type": "KubeletUnhealthy",
"reason": "KubeletIsHealthy",
"message": "kubelet on the node is functioning properly"
}
],
"rules": [
{
"type": "permanent",
"condition": "KubeletUnhealthy",
"reason": "KubeletUnhealthy",
"path": "/home/kubernetes/bin/health-checker",
"args": [
"--component=kubelet",
"--enable-repair=false",
"--cooldown-time=1m",
"--health-check-timeout=10s"
],
"timeout": "3m"
}
]
}
Loading

0 comments on commit 452818c

Please sign in to comment.