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  }