github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubectl/cli.go (about) 1 /* 2 Copyright 2019 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kubectl 18 19 import ( 20 "context" 21 "io" 22 "os/exec" 23 "sync" 24 25 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" 26 ) 27 28 // CLI holds parameters to run kubectl. 29 type CLI struct { 30 KubeContext string 31 KubeConfig string 32 Namespace string 33 34 version ClientVersion 35 versionOnce sync.Once 36 } 37 38 type Config interface { 39 GetKubeContext() string 40 GetKubeConfig() string 41 GetKubeNamespace() string 42 } 43 44 // NewCLI creates a new kubectl CLI whereby the namespace from command 45 // line / environment variable takes precedence over "default namespace" 46 // defined in deployer configuration 47 func NewCLI(cfg Config, defaultNamespace string) *CLI { 48 ns := defaultNamespace 49 if nsFromOpts := cfg.GetKubeNamespace(); nsFromOpts != "" { 50 ns = nsFromOpts 51 } 52 return &CLI{ 53 KubeContext: cfg.GetKubeContext(), 54 KubeConfig: cfg.GetKubeConfig(), 55 Namespace: ns, 56 } 57 } 58 59 // Command creates the underlying exec.CommandContext. This allows low-level control of the executed command. 60 func (c *CLI) Command(ctx context.Context, command string, arg ...string) *exec.Cmd { 61 args := c.args(command, "", arg...) 62 return exec.CommandContext(ctx, "kubectl", args...) 63 } 64 65 // Command creates the underlying exec.CommandContext with namespace. This allows low-level control of the executed command. 66 func (c *CLI) CommandWithNamespaceArg(ctx context.Context, command string, namespace string, arg ...string) *exec.Cmd { 67 args := c.args(command, namespace, arg...) 68 return exec.CommandContext(ctx, "kubectl", args...) 69 } 70 71 // Run shells out kubectl CLI. 72 func (c *CLI) Run(ctx context.Context, in io.Reader, out io.Writer, command string, arg ...string) error { 73 cmd := c.Command(ctx, command, arg...) 74 cmd.Stdin = in 75 cmd.Stdout = out 76 cmd.Stderr = out 77 return util.RunCmd(ctx, cmd) 78 } 79 80 // RunInNamespace shells out kubectl CLI with given namespace 81 func (c *CLI) RunInNamespace(ctx context.Context, in io.Reader, out io.Writer, command string, namespace string, arg ...string) error { 82 cmd := c.CommandWithNamespaceArg(ctx, command, namespace, arg...) 83 cmd.Stdin = in 84 cmd.Stdout = out 85 cmd.Stderr = out 86 return util.RunCmd(ctx, cmd) 87 } 88 89 // RunOut shells out kubectl CLI. 90 func (c *CLI) RunOut(ctx context.Context, command string, arg ...string) ([]byte, error) { 91 cmd := c.Command(ctx, command, arg...) 92 return util.RunCmdOut(ctx, cmd) 93 } 94 95 // RunOutInput shells out kubectl CLI with a given input stream. 96 func (c *CLI) RunOutInput(ctx context.Context, in io.Reader, command string, arg ...string) ([]byte, error) { 97 cmd := c.Command(ctx, command, arg...) 98 cmd.Stdin = in 99 return util.RunCmdOut(ctx, cmd) 100 } 101 102 // CommandWithStrictCancellation ensures for windows OS that all child process get terminated on cancellation 103 func (c *CLI) CommandWithStrictCancellation(ctx context.Context, command string, arg ...string) *Cmd { 104 args := c.args(command, "", arg...) 105 return CommandContext(ctx, "kubectl", args...) 106 } 107 108 // args builds an argument list for calling kubectl and consistently 109 // adds the `--context` and `--namespace` flags. 110 func (c *CLI) args(command string, namespace string, arg ...string) []string { 111 args := []string{"--context", c.KubeContext} 112 namespace = c.resolveNamespace(namespace) 113 if namespace != "" { 114 args = append(args, "--namespace", namespace) 115 } 116 if c.KubeConfig != "" { 117 args = append(args, "--kubeconfig", c.KubeConfig) 118 } 119 args = append(args, command) 120 args = append(args, arg...) 121 return args 122 } 123 124 func (c *CLI) resolveNamespace(ns string) string { 125 if ns != "" { 126 return ns 127 } 128 return c.Namespace 129 }