diff --git a/cmd/node_problem_detector.go b/cmd/node_problem_detector.go index d5a43205..c0249b24 100644 --- a/cmd/node_problem_detector.go +++ b/cmd/node_problem_detector.go @@ -17,11 +17,9 @@ limitations under the License. package main import ( - "flag" "net" "net/http" _ "net/http/pprof" - "net/url" "os" "strconv" @@ -29,57 +27,13 @@ import ( "github.com/spf13/pflag" "k8s.io/node-problem-detector/pkg/kernelmonitor" + "k8s.io/node-problem-detector/pkg/options" + "k8s.io/node-problem-detector/pkg/problemclient" "k8s.io/node-problem-detector/pkg/problemdetector" "k8s.io/node-problem-detector/pkg/version" ) -// TODO: Move flags to options directory. -var ( - kernelMonitorConfigPath = pflag.String("kernel-monitor", "/config/kernel-monitor.json", "The path to the kernel monitor config file") - apiServerOverride = pflag.String("apiserver-override", "", "Custom URI used to connect to Kubernetes ApiServer") - printVersion = pflag.Bool("version", false, "Print version information and quit") - hostnameOverride = pflag.String("hostname-override", "", "Custom node name used to override hostname") - serverPort = pflag.Int("port", 10256, "The port to bind the node problem detector server. Use 0 to disable.") - serverAddress = pflag.String("address", "127.0.0.1", "The address to bind the node problem detector server.") -) - -func validateCmdParams() { - if _, err := url.Parse(*apiServerOverride); err != nil { - glog.Fatalf("apiserver-override %q is not a valid HTTP URI: %v", *apiServerOverride, err) - } -} - -func getNodeNameOrDie() string { - var nodeName string - - // Check hostname override first for customized node name. - if *hostnameOverride != "" { - return *hostnameOverride - } - - // Get node name from environment variable NODE_NAME - // By default, assume that the NODE_NAME env should have been set with - // downward api or user defined exported environment variable. We prefer it because sometimes - // the hostname returned by os.Hostname is not right because: - // 1. User may override the hostname. - // 2. For some cloud providers, os.Hostname is different from the real hostname. - nodeName = os.Getenv("NODE_NAME") - if nodeName != "" { - return nodeName - } - - // For backward compatibility. If the env is not set, get the hostname - // from os.Hostname(). This may not work for all configurations and - // environments. - nodeName, err := os.Hostname() - if err != nil { - glog.Fatalf("Failed to get host name: %v", err) - } - - return nodeName -} - -func startHTTPServer(p problemdetector.ProblemDetector) { +func startHTTPServer(p problemdetector.ProblemDetector, npdo *options.NodeProblemDetectorOptions) { // Add healthz http request handler. Always return ok now, add more health check // logic in the future. http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { @@ -88,31 +42,36 @@ func startHTTPServer(p problemdetector.ProblemDetector) { }) // Add the http handlers in problem detector. p.RegisterHTTPHandlers() - err := http.ListenAndServe(net.JoinHostPort(*serverAddress, strconv.Itoa(*serverPort)), nil) + + addr := net.JoinHostPort(npdo.ServerAddress, strconv.Itoa(npdo.ServerPort)) + err := http.ListenAndServe(addr, nil) if err != nil { glog.Fatalf("Failed to start server: %v", err) } } func main() { - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + npdo := options.NewNodeProblemDetectorOptions() + npdo.AddFlags(pflag.CommandLine) + pflag.Parse() - validateCmdParams() + npdo.SetNodeNameOrDie() - if *printVersion { + npdo.ValidOrDie() + + if npdo.PrintVersion { version.PrintVersion() os.Exit(0) } - nodeName := getNodeNameOrDie() - - k := kernelmonitor.NewKernelMonitorOrDie(*kernelMonitorConfigPath) - p := problemdetector.NewProblemDetector(k, *apiServerOverride, nodeName) + k := kernelmonitor.NewKernelMonitorOrDie(npdo.KernelMonitorConfigPath) + c := problemclient.NewClientOrDie(npdo) + p := problemdetector.NewProblemDetector(k, c) // Start http server. - if *serverPort > 0 { - startHTTPServer(p) + if npdo.ServerPort > 0 { + startHTTPServer(p, npdo) } if err := p.Run(); err != nil { diff --git a/pkg/options/options.go b/pkg/options/options.go new file mode 100644 index 00000000..e9d21f07 --- /dev/null +++ b/pkg/options/options.go @@ -0,0 +1,111 @@ +/* +Copyright 2017 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" + "os" + + "net/url" + + "github.com/spf13/pflag" +) + +// NodeProblemDetectorOptions contains node problem detector command line and application options. +type NodeProblemDetectorOptions struct { + // command line options + + // KernelMonitorConfigPath specifies the path to kernel monitor configuration file. + KernelMonitorConfigPath string + // ApiServerOverride is the custom URI used to connect to Kubernetes ApiServer. + ApiServerOverride string + // PrintVersion is the flag determining whether version information is printed. + PrintVersion bool + // HostnameOverride specifies custom node name used to override hostname. + HostnameOverride string + // ServerPort is the port to bind the node problem detector server. Use 0 to disable. + ServerPort int + // ServerAddress is the address to bind the node problem detector server. + ServerAddress string + + // application options + + // NodeName is the node name used to communicate with Kubernetes ApiServer. + NodeName string +} + +func NewNodeProblemDetectorOptions() *NodeProblemDetectorOptions { + return &NodeProblemDetectorOptions{} +} + +// AddFlags adds node problem detector command line options to pflag. +func (npdo *NodeProblemDetectorOptions) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&npdo.KernelMonitorConfigPath, "kernel-monitor", + "/config/kernel-monitor.json", "The path to the kernel monitor config file") + fs.StringVar(&npdo.ApiServerOverride, "apiserver-override", + "", "Custom URI used to connect to Kubernetes ApiServer") + fs.BoolVar(&npdo.PrintVersion, "version", false, "Print version information and quit") + fs.StringVar(&npdo.HostnameOverride, "hostname-override", + "", "Custom node name used to override hostname") + fs.IntVar(&npdo.ServerPort, "port", + 10256, "The port to bind the node problem detector server. Use 0 to disable.") + fs.StringVar(&npdo.ServerAddress, "address", + "127.0.0.1", "The address to bind the node problem detector server.") +} + +// ValidOrDie validates node problem detector command line options. +func (npdo *NodeProblemDetectorOptions) ValidOrDie() { + if _, err := url.Parse(npdo.ApiServerOverride); err != nil { + panic(fmt.Sprintf("apiserver-override %q is not a valid HTTP URI: %v", + npdo.ApiServerOverride, err)) + } +} + +// SetNodeNameOrDie sets `NodeName` field with valid value. +func (npdo *NodeProblemDetectorOptions) SetNodeNameOrDie() { + // Check hostname override first for customized node name. + if npdo.HostnameOverride != "" { + npdo.NodeName = npdo.HostnameOverride + return + } + + // Get node name from environment variable NODE_NAME + // By default, assume that the NODE_NAME env should have been set with + // downward api or user defined exported environment variable. We prefer it because sometimes + // the hostname returned by os.Hostname is not right because: + // 1. User may override the hostname. + // 2. For some cloud providers, os.Hostname is different from the real hostname. + npdo.NodeName = os.Getenv("NODE_NAME") + if npdo.NodeName != "" { + return + } + + // For backward compatibility. If the env is not set, get the hostname + // from os.Hostname(). This may not work for all configurations and + // environments. + nodeName, err := os.Hostname() + if err != nil { + panic(fmt.Sprintf("Failed to get host name: %v", err)) + } + + npdo.NodeName = nodeName +} + +func init() { + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) +} diff --git a/pkg/problemclient/problem_client.go b/pkg/problemclient/problem_client.go index 90c5af40..49b6af4a 100644 --- a/pkg/problemclient/problem_client.go +++ b/pkg/problemclient/problem_client.go @@ -29,6 +29,7 @@ import ( "k8s.io/kubernetes/pkg/util/clock" "k8s.io/heapster/common/kubernetes" + "k8s.io/node-problem-detector/pkg/options" ) // Client is the interface of problem client @@ -50,11 +51,11 @@ type nodeProblemClient struct { } // NewClientOrDie creates a new problem client, panics if error occurs. -func NewClientOrDie(apiServerOverride, nodeName string) Client { +func NewClientOrDie(npdo *options.NodeProblemDetectorOptions) Client { c := &nodeProblemClient{clock: clock.RealClock{}} // we have checked it is a valid URI after command line argument is parsed.:) - uri, _ := url.Parse(apiServerOverride) + uri, _ := url.Parse(npdo.ApiServerOverride) cfg, err := kubernetes.GetKubeClientConfig(uri) if err != nil { @@ -63,7 +64,7 @@ func NewClientOrDie(apiServerOverride, nodeName string) Client { // TODO(random-liu): Set QPS Limit c.client = client.NewOrDie(cfg) - c.nodeName = nodeName + c.nodeName = npdo.NodeName c.nodeRef = getNodeRef(c.nodeName) c.recorders = make(map[string]record.EventRecorder) return c diff --git a/pkg/problemdetector/problem_detector.go b/pkg/problemdetector/problem_detector.go index e918cc37..82388c9f 100644 --- a/pkg/problemdetector/problem_detector.go +++ b/pkg/problemdetector/problem_detector.go @@ -44,8 +44,7 @@ type problemDetector struct { // NewProblemDetector creates the problem detector. Currently we just directly passed in the problem daemons, but // in the future we may want to let the problem daemons register themselves. -func NewProblemDetector(monitor kernelmonitor.KernelMonitor, apiServerOverride, nodeName string) ProblemDetector { - client := problemclient.NewClientOrDie(apiServerOverride, nodeName) +func NewProblemDetector(monitor kernelmonitor.KernelMonitor, client problemclient.Client) ProblemDetector { return &problemDetector{ client: client, conditionManager: condition.NewConditionManager(client, clock.RealClock{}),