From e48847e6ce8b470355c2bfe6934d63c341231257 Mon Sep 17 00:00:00 2001 From: David Eads Date: Wed, 17 Jan 2018 12:34:04 -0500 Subject: [PATCH] switch hyper to cobra --- cmd/hyperkube/BUILD | 37 +- cmd/hyperkube/cloud-controller-manager.go | 39 -- cmd/hyperkube/hyperkube.go | 281 --------------- cmd/hyperkube/hyperkube_test.go | 338 ------------------ cmd/hyperkube/kube-apiserver.go | 41 --- cmd/hyperkube/kube-controller-manager.go | 40 --- cmd/hyperkube/kube-proxy.go | 54 --- cmd/hyperkube/kube-scheduler.go | 54 --- cmd/hyperkube/kubectl.go | 42 --- cmd/hyperkube/kubelet.go | 50 --- cmd/hyperkube/main.go | 161 ++++++++- cmd/hyperkube/server.go | 77 ---- .../controller-manager.go | 3 + cmd/kube-scheduler/scheduler.go | 2 + cmd/kubectl/kubectl.go | 2 + cmd/kubelet/app/options/globalflags.go | 5 +- 16 files changed, 154 insertions(+), 1072 deletions(-) delete mode 100644 cmd/hyperkube/cloud-controller-manager.go delete mode 100644 cmd/hyperkube/hyperkube.go delete mode 100644 cmd/hyperkube/hyperkube_test.go delete mode 100644 cmd/hyperkube/kube-apiserver.go delete mode 100644 cmd/hyperkube/kube-controller-manager.go delete mode 100644 cmd/hyperkube/kube-proxy.go delete mode 100644 cmd/hyperkube/kube-scheduler.go delete mode 100644 cmd/hyperkube/kubectl.go delete mode 100644 cmd/hyperkube/kubelet.go delete mode 100644 cmd/hyperkube/server.go diff --git a/cmd/hyperkube/BUILD b/cmd/hyperkube/BUILD index f4974ef0d7..bad6cbc2c0 100644 --- a/cmd/hyperkube/BUILD +++ b/cmd/hyperkube/BUILD @@ -4,7 +4,6 @@ load( "@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", - "go_test", ) load("//pkg/version:def.bzl", "version_x_defs") @@ -15,54 +14,22 @@ go_binary( x_defs = version_x_defs(), ) -go_test( - name = "go_default_test", - srcs = ["hyperkube_test.go"], - embed = [":go_default_library"], - importpath = "k8s.io/kubernetes/cmd/hyperkube", - deps = [ - "//vendor/github.com/spf13/cobra:go_default_library", - "//vendor/github.com/stretchr/testify/assert:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", - ], -) - go_library( name = "go_default_library", - srcs = [ - "cloud-controller-manager.go", - "hyperkube.go", - "kube-apiserver.go", - "kube-controller-manager.go", - "kube-proxy.go", - "kube-scheduler.go", - "kubectl.go", - "kubelet.go", - "main.go", - "server.go", - ], + srcs = ["main.go"], importpath = "k8s.io/kubernetes/cmd/hyperkube", deps = [ "//cmd/cloud-controller-manager/app:go_default_library", - "//cmd/cloud-controller-manager/app/options:go_default_library", "//cmd/kube-apiserver/app:go_default_library", - "//cmd/kube-apiserver/app/options:go_default_library", "//cmd/kube-controller-manager/app:go_default_library", - "//cmd/kube-controller-manager/app/options:go_default_library", "//cmd/kube-proxy/app:go_default_library", "//cmd/kube-scheduler/app:go_default_library", "//cmd/kubelet/app:go_default_library", - "//cmd/kubelet/app/options:go_default_library", "//pkg/client/metrics/prometheus:go_default_library", "//pkg/kubectl/cmd:go_default_library", - "//pkg/kubectl/cmd/util:go_default_library", - "//pkg/util/template:go_default_library", "//pkg/version/prometheus:go_default_library", - "//pkg/version/verflag:go_default_library", + "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/logs:go_default_library", ], diff --git a/cmd/hyperkube/cloud-controller-manager.go b/cmd/hyperkube/cloud-controller-manager.go deleted file mode 100644 index fd3266beea..0000000000 --- a/cmd/hyperkube/cloud-controller-manager.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -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 ( - "k8s.io/kubernetes/cmd/cloud-controller-manager/app" - "k8s.io/kubernetes/cmd/cloud-controller-manager/app/options" -) - -// NewCloudControllerManager creates a new hyperkube Server object that includes the -// description and flags. -func NewCloudControllerManager() *Server { - s := options.NewCloudControllerManagerServer() - - hks := Server{ - name: "cloud-controller-manager", - SimpleUsage: "cloud-controller-manager", - Long: "A server that acts as an external cloud provider.", - Run: func(_ *Server, args []string, stopCh <-chan struct{}) error { - return app.Run(s) - }, - } - s.AddFlags(hks.Flags()) - return &hks -} diff --git a/cmd/hyperkube/hyperkube.go b/cmd/hyperkube/hyperkube.go deleted file mode 100644 index a4de5c7af2..0000000000 --- a/cmd/hyperkube/hyperkube.go +++ /dev/null @@ -1,281 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -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 ( - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "path" - - "github.com/spf13/pflag" - - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/server" - utilflag "k8s.io/apiserver/pkg/util/flag" - "k8s.io/apiserver/pkg/util/logs" - utiltemplate "k8s.io/kubernetes/pkg/util/template" - "k8s.io/kubernetes/pkg/version/verflag" -) - -// HyperKube represents a single binary that can morph/manage into multiple -// servers. -type HyperKube struct { - Name string // The executable name, used for help and soft-link invocation - Long string // A long description of the binary. It will be world wrapped before output. - - servers []Server - alphaServers []Server - baseFlags *pflag.FlagSet - out io.Writer - helpFlagVal bool - makeSymlinksFlagVal bool -} - -// AddServer adds a server to the HyperKube object. -func (hk *HyperKube) AddServer(s *Server) { - hk.servers = append(hk.servers, *s) - hk.servers[len(hk.servers)-1].hk = hk -} - -// AddServer adds an alpha server to the HyperKube object. -func (hk *HyperKube) AddAlphaServer(s *Server) { - hk.alphaServers = append(hk.alphaServers, *s) - hk.alphaServers[len(hk.alphaServers)-1].hk = hk -} - -// FindServer will find a specific server named name. -func (hk *HyperKube) FindServer(name string) (*Server, error) { - return findServer(name, hk.servers) -} - -// FindServer will find a specific alpha server named name. -func (hk *HyperKube) FindAlphaServer(name string) (*Server, error) { - return findServer(name, hk.alphaServers) -} - -func findServer(name string, servers []Server) (*Server, error) { - for _, s := range servers { - if s.Name() == name || s.AlternativeName == name { - return &s, nil - } - } - return nil, fmt.Errorf("Server not found: %s", name) -} - -// Servers returns a list of all of the registered servers -func (hk *HyperKube) Servers() []Server { - return hk.servers -} - -// Flags returns a flagset for "global" flags. -func (hk *HyperKube) Flags() *pflag.FlagSet { - if hk.baseFlags == nil { - hk.baseFlags = pflag.NewFlagSet(hk.Name, pflag.ContinueOnError) - hk.baseFlags.SetOutput(ioutil.Discard) - hk.baseFlags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) - hk.baseFlags.BoolVarP(&hk.helpFlagVal, "help", "h", false, "help for "+hk.Name) - hk.baseFlags.BoolVar(&hk.makeSymlinksFlagVal, "make-symlinks", false, "create a symlink for each server in current directory") - hk.baseFlags.MarkHidden("make-symlinks") // hide this flag from appearing in servers' usage output - - // These will add all of the "global" flags (defined with both the - // flag and pflag packages) to the new flag set we have. - hk.baseFlags.AddGoFlagSet(flag.CommandLine) - hk.baseFlags.AddFlagSet(pflag.CommandLine) - - } - return hk.baseFlags -} - -// Out returns the io.Writer that is used for all usage/error information -func (hk *HyperKube) Out() io.Writer { - if hk.out == nil { - hk.out = os.Stderr - } - return hk.out -} - -// SetOut sets the output writer for all usage/error information -func (hk *HyperKube) SetOut(w io.Writer) { - hk.out = w -} - -// Print is a convenience method to Print to the defined output -func (hk *HyperKube) Print(i ...interface{}) { - fmt.Fprint(hk.Out(), i...) -} - -// Println is a convenience method to Println to the defined output -func (hk *HyperKube) Println(i ...interface{}) { - fmt.Fprintln(hk.Out(), i...) -} - -// Printf is a convenience method to Printf to the defined output -func (hk *HyperKube) Printf(format string, i ...interface{}) { - fmt.Fprintf(hk.Out(), format, i...) -} - -// Run the server. This will pick the appropriate server and run it. -func (hk *HyperKube) Run(args []string, stopCh <-chan struct{}) error { - // If we are called directly, parse all flags up to the first real - // argument. That should be the server to run. - command := args[0] - serverName := path.Base(command) - args = args[1:] - if serverName == hk.Name { - - baseFlags := hk.Flags() - baseFlags.SetInterspersed(false) // Only parse flags up to the next real command - err := baseFlags.Parse(args) - if err != nil || hk.helpFlagVal { - if err != nil { - hk.Println("Error:", err) - } - hk.Usage() - return err - } - - if hk.makeSymlinksFlagVal { - return hk.MakeSymlinks(command) - } - - verflag.PrintAndExitIfRequested() - - args = baseFlags.Args() - if len(args) > 0 && len(args[0]) > 0 { - serverName = args[0] - args = args[1:] - } else { - err = errors.New("no server specified") - hk.Printf("Error: %v\n\n", err) - hk.Usage() - return err - } - } - - var s *Server - var err error - if serverName == "alpha" { - if len(args) > 0 && len(args[0]) > 0 { - serverName = args[0] - args = args[1:] - hk.Printf("Warning: alpha command syntax is unstable!\n\n") - } else { - err = errors.New("no alpha server specified") - hk.Printf("Error: %v\n\n", err) - hk.Usage() - return err - } - s, err = hk.FindAlphaServer(serverName) - } else { - s, err = hk.FindServer(serverName) - } - if err != nil { - hk.Printf("Error: %v\n\n", err) - hk.Usage() - return err - } - - s.Flags().AddFlagSet(hk.Flags()) - err = s.Flags().Parse(args) - if err != nil || hk.helpFlagVal { - if err != nil { - hk.Printf("Error: %v\n\n", err) - } - s.Usage() - return err - } - - verflag.PrintAndExitIfRequested() - - logs.InitLogs() - defer logs.FlushLogs() - - if !s.RespectsStopCh { - // For commands that do not respect the stopCh, we run them in a go - // routine and leave them running when stopCh is closed. - errCh := make(chan error) - go func() { - errCh <- s.Run(s, s.Flags().Args(), wait.NeverStop) - }() - select { - case <-stopCh: - return errors.New("interrupted") // This error text is ignored. - case err = <-errCh: - // fall-through - } - } else { - err = s.Run(s, s.Flags().Args(), stopCh) - } - if err != nil { - hk.Println("Error:", err) - } - - return err -} - -// RunToExit will run the hyperkube and then call os.Exit with an appropriate exit code. -func (hk *HyperKube) RunToExit(args []string) { - stopCh := server.SetupSignalHandler() - if err := hk.Run(args, stopCh); err != nil { - os.Exit(1) - } -} - -// Usage will write out a summary for all servers that this binary supports. -func (hk *HyperKube) Usage() { - tt := `{{if .Long}}{{.Long | trim | wrap ""}} -{{end}}Usage - - {{.Name}} [flags] - -Servers -{{range .Servers}} - {{.Name}} -{{.Long | trim | wrap " "}}{{end}} -Call '{{.Name}} --make-symlinks' to create symlinks for each server in the local directory. -Call '{{.Name}} --help' for help on a specific server. -` - utiltemplate.ExecuteTemplate(hk.Out(), tt, hk) -} - -// MakeSymlinks will create a symlink for each registered hyperkube server in the local directory. -func (hk *HyperKube) MakeSymlinks(command string) error { - wd, err := os.Getwd() - if err != nil { - return err - } - - var errs bool - for _, s := range hk.servers { - link := path.Join(wd, s.Name()) - - err := os.Symlink(command, link) - if err != nil { - errs = true - hk.Println(err) - } - } - - if errs { - return errors.New("Error creating one or more symlinks.") - } - return nil -} diff --git a/cmd/hyperkube/hyperkube_test.go b/cmd/hyperkube/hyperkube_test.go deleted file mode 100644 index 5676181201..0000000000 --- a/cmd/hyperkube/hyperkube_test.go +++ /dev/null @@ -1,338 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -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 ( - "bytes" - "errors" - "fmt" - "strings" - "testing" - "time" - - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" - - "k8s.io/apimachinery/pkg/util/wait" -) - -type result struct { - err error - output string -} - -func testServer(n string) *Server { - return &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A simple server named %s", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - s.hk.Printf("%s Run\n", s.Name()) - return nil - }, - } -} -func testServerError(n string) *Server { - return &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A simple server named %s that returns an error", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - s.hk.Printf("%s Run\n", s.Name()) - return errors.New("server returning error") - }, - } -} -func testStopChRespectingServer(n string) *Server { - return &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A simple server named %s", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - s.hk.Printf("%s Run\n", s.Name()) - <-stopCh - return nil - }, - RespectsStopCh: true, - } -} -func testStopChIgnoringServer(n string) *Server { - return &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A simple server named %s", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - <-wait.NeverStop // this leaks obviously, but we don't care about one go routine more or less in test - return nil - }, - RespectsStopCh: false, - } -} -func testStopChRespectingServerWithError(n string) *Server { - return &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A simple server named %s", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - s.hk.Printf("%s Run\n", s.Name()) - <-stopCh - return errors.New("server returning error") - }, - RespectsStopCh: true, - } -} - -const defaultCobraMessage = "default message from cobra command" -const defaultCobraSubMessage = "default sub-message from cobra command" -const cobraMessageDesc = "message to print" -const cobraSubMessageDesc = "sub-message to print" - -func testCobraCommand(n string) *Server { - - var cobraServer *Server - var msg string - cmd := &cobra.Command{ - Use: n, - Long: n, - Short: n, - Run: func(cmd *cobra.Command, args []string) { - cobraServer.hk.Printf("msg: %s\n", msg) - }, - } - cmd.PersistentFlags().StringVar(&msg, "msg", defaultCobraMessage, cobraMessageDesc) - - var subMsg string - subCmdName := "subcommand" - subCmd := &cobra.Command{ - Use: subCmdName, - Long: subCmdName, - Short: subCmdName, - Run: func(cmd *cobra.Command, args []string) { - cobraServer.hk.Printf("submsg: %s", subMsg) - }, - } - subCmd.PersistentFlags().StringVar(&subMsg, "submsg", defaultCobraSubMessage, cobraSubMessageDesc) - - cmd.AddCommand(subCmd) - - localFlags := cmd.LocalFlags() - localFlags.SetInterspersed(false) - s := &Server{ - SimpleUsage: n, - Long: fmt.Sprintf("A server named %s which uses a cobra command", n), - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - cobraServer = s - cmd.SetOutput(s.hk.Out()) - cmd.SetArgs(args) - return cmd.Execute() - }, - flags: localFlags, - } - - return s -} -func runFull(t *testing.T, args string, stopCh <-chan struct{}) *result { - buf := new(bytes.Buffer) - hk := HyperKube{ - Name: "hyperkube", - Long: "hyperkube is an all-in-one server binary.", - } - hk.SetOut(buf) - - hk.AddServer(testServer("test1")) - hk.AddServer(testServer("test2")) - hk.AddServer(testServer("test3")) - hk.AddAlphaServer(testServer("testAlpha1")) - hk.AddServer(testServerError("test-error")) - hk.AddServer(testStopChIgnoringServer("test-stop-ch-ignoring")) - hk.AddServer(testStopChRespectingServer("test-stop-ch-respecting")) - hk.AddServer(testStopChRespectingServerWithError("test-error-stop-ch-respecting")) - hk.AddServer(testCobraCommand("test-cobra-command")) - - a := strings.Split(args, " ") - t.Logf("Running full with args: %q", a) - err := hk.Run(a, stopCh) - - r := &result{err, buf.String()} - t.Logf("Result err: %v, output: %q", r.err, r.output) - - return r -} - -func TestRun(t *testing.T) { - x := runFull(t, "hyperkube test1", wait.NeverStop) - assert.Contains(t, x.output, "test1 Run") - assert.NoError(t, x.err) -} - -func TestLinkRun(t *testing.T) { - x := runFull(t, "test1", wait.NeverStop) - assert.Contains(t, x.output, "test1 Run") - assert.NoError(t, x.err) -} - -func TestTopNoArgs(t *testing.T) { - x := runFull(t, "hyperkube", wait.NeverStop) - assert.EqualError(t, x.err, "no server specified") -} - -func TestBadServer(t *testing.T) { - x := runFull(t, "hyperkube bad-server", wait.NeverStop) - assert.EqualError(t, x.err, "Server not found: bad-server") - assert.Contains(t, x.output, "Usage") -} - -func TestTopHelp(t *testing.T) { - x := runFull(t, "hyperkube --help", wait.NeverStop) - assert.NoError(t, x.err) - assert.Contains(t, x.output, "all-in-one") - assert.Contains(t, x.output, "A simple server named test1") -} - -func TestTopFlags(t *testing.T) { - x := runFull(t, "hyperkube --help test1", wait.NeverStop) - assert.NoError(t, x.err) - assert.Contains(t, x.output, "all-in-one") - assert.Contains(t, x.output, "A simple server named test1") - assert.NotContains(t, x.output, "test1 Run") -} - -func TestTopFlagsBad(t *testing.T) { - x := runFull(t, "hyperkube --bad-flag", wait.NeverStop) - assert.EqualError(t, x.err, "unknown flag: --bad-flag") - assert.Contains(t, x.output, "all-in-one") - assert.Contains(t, x.output, "A simple server named test1") -} - -func TestServerHelp(t *testing.T) { - x := runFull(t, "hyperkube test1 --help", wait.NeverStop) - assert.NoError(t, x.err) - assert.Contains(t, x.output, "A simple server named test1") - assert.Contains(t, x.output, "-h, --help") - assert.Contains(t, x.output, "help for hyperkube") - assert.NotContains(t, x.output, "test1 Run") -} - -func TestServerFlagsBad(t *testing.T) { - x := runFull(t, "hyperkube test1 --bad-flag", wait.NeverStop) - assert.EqualError(t, x.err, "unknown flag: --bad-flag") - assert.Contains(t, x.output, "A simple server named test1") - assert.Contains(t, x.output, "-h, --help") - assert.Contains(t, x.output, "help for hyperkube") - assert.NotContains(t, x.output, "test1 Run") -} - -func TestServerError(t *testing.T) { - x := runFull(t, "hyperkube test-error", wait.NeverStop) - assert.Contains(t, x.output, "test-error Run") - assert.EqualError(t, x.err, "server returning error") -} - -func TestAlphaRun(t *testing.T) { - x := runFull(t, "hyperkube alpha testAlpha1", wait.NeverStop) - assert.NoError(t, x.err) -} - -func TestAlphaNoArgs(t *testing.T) { - x := runFull(t, "hyperkube alpha", wait.NeverStop) - assert.EqualError(t, x.err, "no alpha server specified") -} - -func TestAlphaBadServer(t *testing.T) { - x := runFull(t, "hyperkube alpha bad-server", wait.NeverStop) - assert.EqualError(t, x.err, "Server not found: bad-server") - assert.Contains(t, x.output, "Usage") -} - -func TestStopChIgnoringServer(t *testing.T) { - stopCh := make(chan struct{}) - returnedCh := make(chan struct{}) - var x *result - go func() { - defer close(returnedCh) - x = runFull(t, "hyperkube test-stop-ch-ignoring", stopCh) - }() - close(stopCh) - select { - case <-time.After(wait.ForeverTestTimeout): - t.Fatalf("%q never returned after stopCh was closed", "hyperkube test-stop-ch-ignoring") - case <-returnedCh: - } - // we cannot be sure that the server had a chance to output anything - // assert.Contains(t, x.output, "test-error-stop-ch-ignoring Run") - assert.EqualError(t, x.err, "interrupted") -} - -func TestStopChRespectingServer(t *testing.T) { - stopCh := make(chan struct{}) - returnedCh := make(chan struct{}) - var x *result - go func() { - defer close(returnedCh) - x = runFull(t, "hyperkube test-stop-ch-respecting", stopCh) - }() - close(stopCh) - select { - case <-time.After(wait.ForeverTestTimeout): - t.Fatalf("%q never returned after stopCh was closed", "hyperkube test-stop-ch-respecting") - case <-returnedCh: - } - assert.Contains(t, x.output, "test-stop-ch-respecting Run") - assert.Nil(t, x.err) -} - -func TestStopChRespectingServerWithError(t *testing.T) { - stopCh := make(chan struct{}) - returnedCh := make(chan struct{}) - var x *result - go func() { - defer close(returnedCh) - x = runFull(t, "hyperkube test-error-stop-ch-respecting", stopCh) - }() - close(stopCh) - select { - case <-time.After(wait.ForeverTestTimeout): - t.Fatalf("%q never returned after stopCh was closed", "hyperkube test-error-stop-ch-respecting") - case <-returnedCh: - } - assert.Contains(t, x.output, "test-error-stop-ch-respecting Run") - assert.EqualError(t, x.err, "server returning error") -} - -func TestCobraCommandHelp(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command --help", wait.NeverStop) - assert.NoError(t, x.err) - assert.Contains(t, x.output, "A server named test-cobra-command which uses a cobra command") - assert.Contains(t, x.output, cobraMessageDesc) -} -func TestCobraCommandDefaultMessage(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command", wait.NeverStop) - assert.Contains(t, x.output, fmt.Sprintf("msg: %s", defaultCobraMessage)) -} -func TestCobraCommandMessage(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command --msg foobar", wait.NeverStop) - assert.Contains(t, x.output, "msg: foobar") -} - -func TestCobraSubCommandHelp(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command subcommand --help", wait.NeverStop) - assert.NoError(t, x.err) - assert.Contains(t, x.output, cobraSubMessageDesc) -} -func TestCobraSubCommandDefaultMessage(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command subcommand", wait.NeverStop) - assert.Contains(t, x.output, fmt.Sprintf("submsg: %s", defaultCobraSubMessage)) -} -func TestCobraSubCommandMessage(t *testing.T) { - x := runFull(t, "hyperkube test-cobra-command subcommand --submsg foobar", wait.NeverStop) - assert.Contains(t, x.output, "submsg: foobar") -} diff --git a/cmd/hyperkube/kube-apiserver.go b/cmd/hyperkube/kube-apiserver.go deleted file mode 100644 index 160ce22ac5..0000000000 --- a/cmd/hyperkube/kube-apiserver.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 ( - "k8s.io/kubernetes/cmd/kube-apiserver/app" - "k8s.io/kubernetes/cmd/kube-apiserver/app/options" -) - -// NewKubeAPIServer creates a new hyperkube Server object that includes the -// description and flags. -func NewKubeAPIServer() *Server { - s := options.NewServerRunOptions() - - hks := Server{ - name: "apiserver", - AlternativeName: "kube-apiserver", - SimpleUsage: "apiserver", - Long: "The main API entrypoint and interface to the storage system. The API server is also the focal point for all authorization decisions.", - Run: func(_ *Server, args []string, stopCh <-chan struct{}) error { - return app.Run(s, stopCh) - }, - RespectsStopCh: true, - } - s.AddFlags(hks.Flags()) - return &hks -} diff --git a/cmd/hyperkube/kube-controller-manager.go b/cmd/hyperkube/kube-controller-manager.go deleted file mode 100644 index c69cb99084..0000000000 --- a/cmd/hyperkube/kube-controller-manager.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 ( - "k8s.io/kubernetes/cmd/kube-controller-manager/app" - "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" -) - -// NewKubeControllerManager creates a new hyperkube Server object that includes the -// description and flags. -func NewKubeControllerManager() *Server { - s := options.NewCMServer() - - hks := Server{ - name: "controller-manager", - AlternativeName: "kube-controller-manager", - SimpleUsage: "controller-manager", - Long: "A server that runs a set of active components. This includes replication controllers, service endpoints and nodes.", - Run: func(_ *Server, args []string, stopCh <-chan struct{}) error { - return app.Run(s) - }, - } - s.AddFlags(hks.Flags(), app.KnownControllers(), app.ControllersDisabledByDefault.List()) - return &hks -} diff --git a/cmd/hyperkube/kube-proxy.go b/cmd/hyperkube/kube-proxy.go deleted file mode 100644 index cd5b5d45d4..0000000000 --- a/cmd/hyperkube/kube-proxy.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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" - - "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/kubernetes/cmd/kube-proxy/app" -) - -// NewKubeProxy creates a new hyperkube Server object that includes the -// description and flags. -func NewKubeProxy() *Server { - healthz.DefaultHealthz() - - command := app.NewProxyCommand() - - hks := Server{ - name: "proxy", - AlternativeName: "kube-proxy", - SimpleUsage: "proxy", - Long: command.Long, - } - - serverFlags := hks.Flags() - serverFlags.AddFlagSet(command.Flags()) - - // FIXME this is here because hyperkube does its own flag parsing, and we need - // the command to know about the go flag set. Remove this once hyperkube is - // refactored to use cobra throughout. - command.Flags().AddGoFlagSet(flag.CommandLine) - - hks.Run = func(_ *Server, args []string, stopCh <-chan struct{}) error { - command.SetArgs(args) - return command.Execute() - } - - return &hks -} diff --git a/cmd/hyperkube/kube-scheduler.go b/cmd/hyperkube/kube-scheduler.go deleted file mode 100644 index ba48aebb2b..0000000000 --- a/cmd/hyperkube/kube-scheduler.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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" - - "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/kubernetes/cmd/kube-scheduler/app" -) - -// NewScheduler creates a new hyperkube Server object that includes the -// description and flags. -func NewScheduler() *Server { - healthz.DefaultHealthz() - - command := app.NewSchedulerCommand() - - hks := Server{ - name: "scheduler", - AlternativeName: "kube-scheduler", - SimpleUsage: "scheduler", - Long: command.Long, - } - - serverFlags := hks.Flags() - serverFlags.AddFlagSet(command.Flags()) - - // FIXME this is here because hyperkube does its own flag parsing, and we need - // the command to know about the go flag set. Remove this once hyperkube is - // refactored to use cobra throughout. - command.Flags().AddGoFlagSet(flag.CommandLine) - - hks.Run = func(_ *Server, args []string, stopCh <-chan struct{}) error { - command.SetArgs(args) - return command.Execute() - } - - return &hks -} diff --git a/cmd/hyperkube/kubectl.go b/cmd/hyperkube/kubectl.go deleted file mode 100644 index 239d585a77..0000000000 --- a/cmd/hyperkube/kubectl.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 ( - "os" - - "k8s.io/kubernetes/pkg/kubectl/cmd" - cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" -) - -// Create a Server that implements the kubectl command -func NewKubectlServer() *Server { - cmd := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr) - localFlags := cmd.LocalFlags() - localFlags.SetInterspersed(false) - - return &Server{ - name: "kubectl", - SimpleUsage: "Kubernetes command line client", - Long: "Kubernetes command line client", - Run: func(s *Server, args []string, stopCh <-chan struct{}) error { - cmd.SetArgs(args) - return cmd.Execute() - }, - flags: localFlags, - } -} diff --git a/cmd/hyperkube/kubelet.go b/cmd/hyperkube/kubelet.go deleted file mode 100644 index c58363a6c9..0000000000 --- a/cmd/hyperkube/kubelet.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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 ( - "k8s.io/kubernetes/cmd/kubelet/app" - "k8s.io/kubernetes/cmd/kubelet/app/options" -) - -// NewKubelet creates a new hyperkube Server object that includes the -// description and flags. -func NewKubelet() (*Server, error) { - s, err := options.NewKubeletServer() - if err != nil { - return nil, err - } - - hks := Server{ - name: "kubelet", - SimpleUsage: "kubelet", - Long: `The kubelet binary is responsible for maintaining a set of containers on a - particular node. It syncs data from a variety of sources including a - Kubernetes API server, an etcd cluster, HTTP endpoint or local file. It then - queries Docker to see what is currently running. It synchronizes the - configuration data, with the running set of containers by starting or stopping - Docker containers.`, - Run: func(_ *Server, _ []string, stopCh <-chan struct{}) error { - if s.ExperimentalDockershim { - return app.RunDockershim(&s.KubeletFlags, &s.KubeletConfiguration) - } - return app.Run(s, nil) - }, - } - s.AddFlags(hks.Flags()) - return &hks, nil -} diff --git a/cmd/hyperkube/main.go b/cmd/hyperkube/main.go index 0bdd55f9a4..1c5a276eae 100644 --- a/cmd/hyperkube/main.go +++ b/cmd/hyperkube/main.go @@ -20,33 +20,156 @@ limitations under the License. package main import ( + "errors" + goflag "flag" "fmt" + "math/rand" "os" + "path" + "path/filepath" + "time" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + utilflag "k8s.io/apiserver/pkg/util/flag" + "k8s.io/apiserver/pkg/util/logs" + cloudcontrollermanager "k8s.io/kubernetes/cmd/cloud-controller-manager/app" + kubeapiserver "k8s.io/kubernetes/cmd/kube-apiserver/app" + kubecontrollermanager "k8s.io/kubernetes/cmd/kube-controller-manager/app" + kubeproxy "k8s.io/kubernetes/cmd/kube-proxy/app" + kubescheduler "k8s.io/kubernetes/cmd/kube-scheduler/app" + kubelet "k8s.io/kubernetes/cmd/kubelet/app" _ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration - _ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration + kubectl "k8s.io/kubernetes/pkg/kubectl/cmd" + _ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration ) func main() { - hk := HyperKube{ - Name: "hyperkube", - Long: "This is an all-in-one binary that can run any of the various Kubernetes servers.", - } + rand.Seed(time.Now().UTC().UnixNano()) - hk.AddServer(NewKubectlServer()) - hk.AddServer(NewKubeAPIServer()) - hk.AddServer(NewKubeControllerManager()) - hk.AddServer(NewScheduler()) - if kubelet, err := NewKubelet(); err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err) + hyperkubeCommand, allCommandFns := NewHyperKubeCommand() + + // TODO: once we switch everything over to Cobra commands, we can go back to calling + // utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the + // normalize func and add the go flag set by hand. + pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) + pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) + // utilflag.InitFlags() + logs.InitLogs() + defer logs.FlushLogs() + + basename := filepath.Base(os.Args[0]) + if err := commandFor(basename, hyperkubeCommand, allCommandFns).Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) - } else { - hk.AddServer(kubelet) } - hk.AddServer(NewKubeProxy()) - - // Alpha servers - hk.AddAlphaServer(NewCloudControllerManager()) - - hk.RunToExit(os.Args) +} + +func commandFor(basename string, defaultCommand *cobra.Command, commands []func() *cobra.Command) *cobra.Command { + for _, commandFn := range commands { + command := commandFn() + if command.Name() == basename { + return command + } + for _, alias := range command.Aliases { + if alias == basename { + return command + } + } + } + + return defaultCommand +} + +// NewCmdRequestProject implement the OpenShift cli RequestProject command. +func NewHyperKubeCommand() (*cobra.Command, []func() *cobra.Command) { + // these have to be functions since the command is polymorphic. Cobra wants you to be top level + // command to get executed + apiserver := func() *cobra.Command { + ret := kubeapiserver.NewAPIServerCommand() + // add back some unfortunate aliases that should be removed + ret.Aliases = []string{"apiserver"} + return ret + } + controller := func() *cobra.Command { + ret := kubecontrollermanager.NewControllerManagerCommand() + // add back some unfortunate aliases that should be removed + ret.Aliases = []string{"controller-manager"} + return ret + } + proxy := func() *cobra.Command { + ret := kubeproxy.NewProxyCommand() + // add back some unfortunate aliases that should be removed + ret.Aliases = []string{"proxy"} + return ret + } + scheduler := func() *cobra.Command { + ret := kubescheduler.NewSchedulerCommand() + // add back some unfortunate aliases that should be removed + ret.Aliases = []string{"scheduler"} + return ret + } + kubectlCmd := func() *cobra.Command { return kubectl.NewDefaultKubectlCommand() } + kubelet := func() *cobra.Command { return kubelet.NewKubeletCommand() } + cloudController := func() *cobra.Command { return cloudcontrollermanager.NewCloudControllerManagerCommand() } + + commandFns := []func() *cobra.Command{ + apiserver, + controller, + proxy, + scheduler, + kubectlCmd, + kubelet, + cloudController, + } + + makeSymlinksFlag := false + cmd := &cobra.Command{ + Use: "hyperkube", + Short: "Request a new project", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 0 || !makeSymlinksFlag { + cmd.Help() + os.Exit(1) + } + + if err := makeSymlinks(os.Args[0], commandFns); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err.Error()) + } + }, + } + cmd.Flags().BoolVar(&makeSymlinksFlag, "make-symlinks", makeSymlinksFlag, "create a symlink for each server in current directory") + cmd.Flags().MarkHidden("make-symlinks") // hide this flag from appearing in servers' usage output + + for i := range commandFns { + cmd.AddCommand(commandFns[i]()) + } + + return cmd, commandFns +} + +// makeSymlinks will create a symlink for each command in the local directory. +func makeSymlinks(targetName string, commandFns []func() *cobra.Command) error { + wd, err := os.Getwd() + if err != nil { + return err + } + + var errs bool + for _, commandFn := range commandFns { + command := commandFn() + link := path.Join(wd, command.Name()) + + err := os.Symlink(targetName, link) + if err != nil { + errs = true + fmt.Println(err) + } + } + + if errs { + return errors.New("Error creating one or more symlinks.") + } + return nil } diff --git a/cmd/hyperkube/server.go b/cmd/hyperkube/server.go deleted file mode 100644 index ff1b260d6c..0000000000 --- a/cmd/hyperkube/server.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -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 ( - "io/ioutil" - "strings" - - "k8s.io/apiserver/pkg/util/flag" - utiltemplate "k8s.io/kubernetes/pkg/util/template" - - "github.com/spf13/pflag" -) - -type serverRunFunc func(s *Server, args []string, stopCh <-chan struct{}) error - -// Server describes a server that this binary can morph into. -type Server struct { - SimpleUsage string // One line description of the server. - Long string // Longer free form description of the server - Run serverRunFunc // Run the server. This is not expected to return. - AlternativeName string - RespectsStopCh bool - - flags *pflag.FlagSet // Flags for the command (and all dependents) - name string - hk *HyperKube -} - -// Usage returns the full usage string including all of the flags. -func (s *Server) Usage() error { - tt := `{{if .Long}}{{.Long | trim | wrap ""}} -{{end}}Usage: - {{.SimpleUsage}} [flags] - -Available Flags: -{{.Flags.FlagUsages}}` - - return utiltemplate.ExecuteTemplate(s.hk.Out(), tt, s) -} - -// Name returns the name of the command as derived from the usage line. -func (s *Server) Name() string { - if s.name != "" { - return s.name - } - name := s.SimpleUsage - i := strings.Index(name, " ") - if i >= 0 { - name = name[:i] - } - return name -} - -// Flags returns a flagset for this server -func (s *Server) Flags() *pflag.FlagSet { - if s.flags == nil { - s.flags = pflag.NewFlagSet(s.Name(), pflag.ContinueOnError) - s.flags.SetOutput(ioutil.Discard) - s.flags.SetNormalizeFunc(flag.WordSepNormalizeFunc) - } - return s.flags -} diff --git a/cmd/kube-controller-manager/controller-manager.go b/cmd/kube-controller-manager/controller-manager.go index bd7c3f62ab..c537a672d4 100644 --- a/cmd/kube-controller-manager/controller-manager.go +++ b/cmd/kube-controller-manager/controller-manager.go @@ -28,6 +28,8 @@ import ( "github.com/spf13/pflag" + "fmt" + utilflag "k8s.io/apiserver/pkg/util/flag" "k8s.io/apiserver/pkg/util/logs" "k8s.io/kubernetes/cmd/kube-controller-manager/app" @@ -52,6 +54,7 @@ func main() { defer logs.FlushLogs() if err := command.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } diff --git a/cmd/kube-scheduler/scheduler.go b/cmd/kube-scheduler/scheduler.go index a925ced373..737d9b2a24 100644 --- a/cmd/kube-scheduler/scheduler.go +++ b/cmd/kube-scheduler/scheduler.go @@ -18,6 +18,7 @@ package main import ( goflag "flag" + "fmt" "math/rand" "os" "time" @@ -45,6 +46,7 @@ func main() { defer logs.FlushLogs() if err := command.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } diff --git a/cmd/kubectl/kubectl.go b/cmd/kubectl/kubectl.go index 4802021b54..5c89e669bb 100644 --- a/cmd/kubectl/kubectl.go +++ b/cmd/kubectl/kubectl.go @@ -18,6 +18,7 @@ package main import ( goflag "flag" + "fmt" "math/rand" "os" "time" @@ -44,6 +45,7 @@ func main() { defer logs.FlushLogs() if err := command.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } diff --git a/cmd/kubelet/app/options/globalflags.go b/cmd/kubelet/app/options/globalflags.go index ad70a30374..3f38264e64 100644 --- a/cmd/kubelet/app/options/globalflags.go +++ b/cmd/kubelet/app/options/globalflags.go @@ -53,8 +53,9 @@ func normalize(s string) string { // register adds a flag to local that targets the Value associated with the Flag named globalName in global func register(global *flag.FlagSet, local *pflag.FlagSet, globalName string) { if f := global.Lookup(globalName); f != nil { - f.Name = normalize(f.Name) - local.AddFlag(pflag.PFlagFromGoFlag(f)) + pflagFlag := pflag.PFlagFromGoFlag(f) + pflagFlag.Name = normalize(pflagFlag.Name) + local.AddFlag(pflagFlag) } else { panic(fmt.Sprintf("failed to find flag in global flagset (flag): %s", globalName)) }